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,156 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
|
|
6
|
+
require_relative "player_comparison_stat"
|
|
7
|
+
|
|
8
|
+
module NBA
|
|
9
|
+
# Provides methods to compare two players
|
|
10
|
+
module PlayerCompare
|
|
11
|
+
# Result set name for overall comparison
|
|
12
|
+
# @return [String] the result set name
|
|
13
|
+
OVERALL_COMPARE = "OverallCompare".freeze
|
|
14
|
+
|
|
15
|
+
# Season type constant for regular season
|
|
16
|
+
# @return [String] the season type
|
|
17
|
+
REGULAR_SEASON = "Regular Season".freeze
|
|
18
|
+
|
|
19
|
+
# Season type constant for playoffs
|
|
20
|
+
# @return [String] the season type
|
|
21
|
+
PLAYOFFS = "Playoffs".freeze
|
|
22
|
+
|
|
23
|
+
# Compares two players overall stats
|
|
24
|
+
#
|
|
25
|
+
# @api public
|
|
26
|
+
# @example
|
|
27
|
+
# stats = NBA::PlayerCompare.compare(
|
|
28
|
+
# player: 201939,
|
|
29
|
+
# vs_player: 2544,
|
|
30
|
+
# season: 2024
|
|
31
|
+
# )
|
|
32
|
+
# stats.each { |s| puts "#{s.full_name}: #{s.pts} ppg" }
|
|
33
|
+
# @param player [Integer, Player] the first player ID or Player object
|
|
34
|
+
# @param vs_player [Integer, Player] the second player ID or Player object
|
|
35
|
+
# @param season [Integer] the season year
|
|
36
|
+
# @param season_type [String] the season type
|
|
37
|
+
# @param client [Client] the API client to use
|
|
38
|
+
# @return [Collection] a collection of comparison stats
|
|
39
|
+
def self.compare(player:, vs_player:, season: Utils.current_season, season_type: REGULAR_SEASON, client: CLIENT)
|
|
40
|
+
player_id = extract_player_id(player)
|
|
41
|
+
vs_player_id = extract_player_id(vs_player)
|
|
42
|
+
path = build_path(player_id, vs_player_id, season, season_type)
|
|
43
|
+
response = client.get(path)
|
|
44
|
+
parse_response(response)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Builds the API request path
|
|
48
|
+
# @api private
|
|
49
|
+
# @return [String] the request path
|
|
50
|
+
def self.build_path(player_id, vs_player_id, season, season_type)
|
|
51
|
+
season_str = Utils.format_season(season)
|
|
52
|
+
encoded_type = season_type
|
|
53
|
+
"playercompare?PlayerIDList=#{player_id}&VsPlayerIDList=#{vs_player_id}" \
|
|
54
|
+
"&Season=#{season_str}&SeasonType=#{encoded_type}&PerMode=PerGame&LeagueID=00"
|
|
55
|
+
end
|
|
56
|
+
private_class_method :build_path
|
|
57
|
+
|
|
58
|
+
# Parses the API response into comparison stat objects
|
|
59
|
+
# @api private
|
|
60
|
+
# @return [Collection] collection of comparison stats
|
|
61
|
+
def self.parse_response(response)
|
|
62
|
+
return Collection.new unless response
|
|
63
|
+
|
|
64
|
+
data = JSON.parse(response)
|
|
65
|
+
result_set = find_result_set(data)
|
|
66
|
+
return Collection.new unless result_set
|
|
67
|
+
|
|
68
|
+
headers = result_set["headers"]
|
|
69
|
+
rows = result_set["rowSet"]
|
|
70
|
+
return Collection.new unless headers && rows
|
|
71
|
+
|
|
72
|
+
stats = rows.map { |row| build_comparison_stat(headers, row) }
|
|
73
|
+
Collection.new(stats)
|
|
74
|
+
end
|
|
75
|
+
private_class_method :parse_response
|
|
76
|
+
|
|
77
|
+
# Finds the overall compare result set in the response
|
|
78
|
+
# @api private
|
|
79
|
+
# @return [Hash, nil] the result set hash
|
|
80
|
+
def self.find_result_set(data)
|
|
81
|
+
result_sets = data["resultSets"]
|
|
82
|
+
return unless result_sets
|
|
83
|
+
|
|
84
|
+
result_sets.find { |rs| rs["name"].eql?(OVERALL_COMPARE) }
|
|
85
|
+
end
|
|
86
|
+
private_class_method :find_result_set
|
|
87
|
+
|
|
88
|
+
# Builds a PlayerComparisonStat object from raw data
|
|
89
|
+
# @api private
|
|
90
|
+
# @return [PlayerComparisonStat] the comparison stat object
|
|
91
|
+
def self.build_comparison_stat(headers, row)
|
|
92
|
+
data = headers.zip(row).to_h
|
|
93
|
+
PlayerComparisonStat.new(**comparison_attributes(data))
|
|
94
|
+
end
|
|
95
|
+
private_class_method :build_comparison_stat
|
|
96
|
+
|
|
97
|
+
# Combines all comparison attributes
|
|
98
|
+
# @api private
|
|
99
|
+
# @return [Hash] the combined attributes
|
|
100
|
+
def self.comparison_attributes(data)
|
|
101
|
+
identity_attributes(data).merge(shooting_attributes(data), counting_attributes(data), advanced_attributes(data))
|
|
102
|
+
end
|
|
103
|
+
private_class_method :comparison_attributes
|
|
104
|
+
|
|
105
|
+
# Extracts identity attributes from data
|
|
106
|
+
# @api private
|
|
107
|
+
# @return [Hash] identity attributes
|
|
108
|
+
def self.identity_attributes(data)
|
|
109
|
+
{player_id: data.fetch("PLAYER_ID"), first_name: data.fetch("FIRST_NAME"),
|
|
110
|
+
last_name: data.fetch("LAST_NAME"), season_id: data.fetch("SEASON_ID"),
|
|
111
|
+
gp: data.fetch("GP"), min: data.fetch("MIN")}
|
|
112
|
+
end
|
|
113
|
+
private_class_method :identity_attributes
|
|
114
|
+
|
|
115
|
+
# Extracts shooting attributes from data
|
|
116
|
+
# @api private
|
|
117
|
+
# @return [Hash] shooting attributes
|
|
118
|
+
def self.shooting_attributes(data)
|
|
119
|
+
{fgm: data.fetch("FGM"), fga: data.fetch("FGA"), fg_pct: data.fetch("FG_PCT"),
|
|
120
|
+
fg3m: data.fetch("FG3M"), fg3a: data.fetch("FG3A"), fg3_pct: data.fetch("FG3_PCT"),
|
|
121
|
+
ftm: data.fetch("FTM"), fta: data.fetch("FTA"), ft_pct: data.fetch("FT_PCT")}
|
|
122
|
+
end
|
|
123
|
+
private_class_method :shooting_attributes
|
|
124
|
+
|
|
125
|
+
# Extracts counting stats attributes from data
|
|
126
|
+
# @api private
|
|
127
|
+
# @return [Hash] counting attributes
|
|
128
|
+
def self.counting_attributes(data)
|
|
129
|
+
{oreb: data.fetch("OREB"), dreb: data.fetch("DREB"), reb: data.fetch("REB"),
|
|
130
|
+
ast: data.fetch("AST"), stl: data.fetch("STL"), blk: data.fetch("BLK"),
|
|
131
|
+
tov: data.fetch("TOV"), pf: data.fetch("PF"), pts: data.fetch("PTS")}
|
|
132
|
+
end
|
|
133
|
+
private_class_method :counting_attributes
|
|
134
|
+
|
|
135
|
+
# Extracts advanced stats attributes from data
|
|
136
|
+
# @api private
|
|
137
|
+
# @return [Hash] advanced attributes
|
|
138
|
+
def self.advanced_attributes(data)
|
|
139
|
+
{eff: data.fetch("EFF"), ast_tov: data.fetch("AST_TOV"), stl_tov: data.fetch("STL_TOV")}
|
|
140
|
+
end
|
|
141
|
+
private_class_method :advanced_attributes
|
|
142
|
+
|
|
143
|
+
# Extracts player ID from a Player object or returns the integer
|
|
144
|
+
#
|
|
145
|
+
# @api private
|
|
146
|
+
# @param player [Player, Integer] the player or player ID
|
|
147
|
+
# @return [Integer] the player ID
|
|
148
|
+
def self.extract_player_id(player)
|
|
149
|
+
case player
|
|
150
|
+
when Player then player.id
|
|
151
|
+
else player
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
private_class_method :extract_player_id
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
module NBA
|
|
2
|
+
# Represents a player comparison stat line
|
|
3
|
+
class PlayerComparisonStat < Shale::Mapper
|
|
4
|
+
include Equalizer.new(:player_id, :season_id)
|
|
5
|
+
|
|
6
|
+
# @!attribute [rw] player_id
|
|
7
|
+
# Returns the player ID
|
|
8
|
+
# @api public
|
|
9
|
+
# @example
|
|
10
|
+
# stat.player_id #=> 201939
|
|
11
|
+
# @return [Integer] the player ID
|
|
12
|
+
attribute :player_id, Shale::Type::Integer
|
|
13
|
+
|
|
14
|
+
# @!attribute [rw] first_name
|
|
15
|
+
# Returns the player's first name
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# stat.first_name #=> "Stephen"
|
|
19
|
+
# @return [String] the first name
|
|
20
|
+
attribute :first_name, Shale::Type::String
|
|
21
|
+
|
|
22
|
+
# @!attribute [rw] last_name
|
|
23
|
+
# Returns the player's last name
|
|
24
|
+
# @api public
|
|
25
|
+
# @example
|
|
26
|
+
# stat.last_name #=> "Curry"
|
|
27
|
+
# @return [String] the last name
|
|
28
|
+
attribute :last_name, Shale::Type::String
|
|
29
|
+
|
|
30
|
+
# @!attribute [rw] season_id
|
|
31
|
+
# Returns the season ID
|
|
32
|
+
# @api public
|
|
33
|
+
# @example
|
|
34
|
+
# stat.season_id #=> "2024-25"
|
|
35
|
+
# @return [String] the season ID
|
|
36
|
+
attribute :season_id, Shale::Type::String
|
|
37
|
+
|
|
38
|
+
# @!attribute [rw] gp
|
|
39
|
+
# Returns games played
|
|
40
|
+
# @api public
|
|
41
|
+
# @example
|
|
42
|
+
# stat.gp #=> 74
|
|
43
|
+
# @return [Integer] games played
|
|
44
|
+
attribute :gp, Shale::Type::Integer
|
|
45
|
+
|
|
46
|
+
# @!attribute [rw] min
|
|
47
|
+
# Returns minutes per game
|
|
48
|
+
# @api public
|
|
49
|
+
# @example
|
|
50
|
+
# stat.min #=> 32.5
|
|
51
|
+
# @return [Float] minutes per game
|
|
52
|
+
attribute :min, Shale::Type::Float
|
|
53
|
+
|
|
54
|
+
# @!attribute [rw] fgm
|
|
55
|
+
# Returns field goals made per game
|
|
56
|
+
# @api public
|
|
57
|
+
# @example
|
|
58
|
+
# stat.fgm #=> 8.5
|
|
59
|
+
# @return [Float] field goals made
|
|
60
|
+
attribute :fgm, Shale::Type::Float
|
|
61
|
+
|
|
62
|
+
# @!attribute [rw] fga
|
|
63
|
+
# Returns field goals attempted per game
|
|
64
|
+
# @api public
|
|
65
|
+
# @example
|
|
66
|
+
# stat.fga #=> 17.2
|
|
67
|
+
# @return [Float] field goals attempted
|
|
68
|
+
attribute :fga, Shale::Type::Float
|
|
69
|
+
|
|
70
|
+
# @!attribute [rw] fg_pct
|
|
71
|
+
# Returns field goal percentage
|
|
72
|
+
# @api public
|
|
73
|
+
# @example
|
|
74
|
+
# stat.fg_pct #=> 0.494
|
|
75
|
+
# @return [Float] field goal percentage
|
|
76
|
+
attribute :fg_pct, Shale::Type::Float
|
|
77
|
+
|
|
78
|
+
# @!attribute [rw] fg3m
|
|
79
|
+
# Returns three-pointers made per game
|
|
80
|
+
# @api public
|
|
81
|
+
# @example
|
|
82
|
+
# stat.fg3m #=> 4.8
|
|
83
|
+
# @return [Float] three-pointers made
|
|
84
|
+
attribute :fg3m, Shale::Type::Float
|
|
85
|
+
|
|
86
|
+
# @!attribute [rw] fg3a
|
|
87
|
+
# Returns three-pointers attempted per game
|
|
88
|
+
# @api public
|
|
89
|
+
# @example
|
|
90
|
+
# stat.fg3a #=> 11.5
|
|
91
|
+
# @return [Float] three-pointers attempted
|
|
92
|
+
attribute :fg3a, Shale::Type::Float
|
|
93
|
+
|
|
94
|
+
# @!attribute [rw] fg3_pct
|
|
95
|
+
# Returns three-point percentage
|
|
96
|
+
# @api public
|
|
97
|
+
# @example
|
|
98
|
+
# stat.fg3_pct #=> 0.417
|
|
99
|
+
# @return [Float] three-point percentage
|
|
100
|
+
attribute :fg3_pct, Shale::Type::Float
|
|
101
|
+
|
|
102
|
+
# @!attribute [rw] ftm
|
|
103
|
+
# Returns free throws made per game
|
|
104
|
+
# @api public
|
|
105
|
+
# @example
|
|
106
|
+
# stat.ftm #=> 4.2
|
|
107
|
+
# @return [Float] free throws made
|
|
108
|
+
attribute :ftm, Shale::Type::Float
|
|
109
|
+
|
|
110
|
+
# @!attribute [rw] fta
|
|
111
|
+
# Returns free throws attempted per game
|
|
112
|
+
# @api public
|
|
113
|
+
# @example
|
|
114
|
+
# stat.fta #=> 4.6
|
|
115
|
+
# @return [Float] free throws attempted
|
|
116
|
+
attribute :fta, Shale::Type::Float
|
|
117
|
+
|
|
118
|
+
# @!attribute [rw] ft_pct
|
|
119
|
+
# Returns free throw percentage
|
|
120
|
+
# @api public
|
|
121
|
+
# @example
|
|
122
|
+
# stat.ft_pct #=> 0.913
|
|
123
|
+
# @return [Float] free throw percentage
|
|
124
|
+
attribute :ft_pct, Shale::Type::Float
|
|
125
|
+
|
|
126
|
+
# @!attribute [rw] oreb
|
|
127
|
+
# Returns offensive rebounds per game
|
|
128
|
+
# @api public
|
|
129
|
+
# @example
|
|
130
|
+
# stat.oreb #=> 0.5
|
|
131
|
+
# @return [Float] offensive rebounds
|
|
132
|
+
attribute :oreb, Shale::Type::Float
|
|
133
|
+
|
|
134
|
+
# @!attribute [rw] dreb
|
|
135
|
+
# Returns defensive rebounds per game
|
|
136
|
+
# @api public
|
|
137
|
+
# @example
|
|
138
|
+
# stat.dreb #=> 4.3
|
|
139
|
+
# @return [Float] defensive rebounds
|
|
140
|
+
attribute :dreb, Shale::Type::Float
|
|
141
|
+
|
|
142
|
+
# @!attribute [rw] reb
|
|
143
|
+
# Returns total rebounds per game
|
|
144
|
+
# @api public
|
|
145
|
+
# @example
|
|
146
|
+
# stat.reb #=> 4.8
|
|
147
|
+
# @return [Float] total rebounds
|
|
148
|
+
attribute :reb, Shale::Type::Float
|
|
149
|
+
|
|
150
|
+
# @!attribute [rw] ast
|
|
151
|
+
# Returns assists per game
|
|
152
|
+
# @api public
|
|
153
|
+
# @example
|
|
154
|
+
# stat.ast #=> 6.1
|
|
155
|
+
# @return [Float] assists
|
|
156
|
+
attribute :ast, Shale::Type::Float
|
|
157
|
+
|
|
158
|
+
# @!attribute [rw] stl
|
|
159
|
+
# Returns steals per game
|
|
160
|
+
# @api public
|
|
161
|
+
# @example
|
|
162
|
+
# stat.stl #=> 0.9
|
|
163
|
+
# @return [Float] steals
|
|
164
|
+
attribute :stl, Shale::Type::Float
|
|
165
|
+
|
|
166
|
+
# @!attribute [rw] blk
|
|
167
|
+
# Returns blocks per game
|
|
168
|
+
# @api public
|
|
169
|
+
# @example
|
|
170
|
+
# stat.blk #=> 0.3
|
|
171
|
+
# @return [Float] blocks
|
|
172
|
+
attribute :blk, Shale::Type::Float
|
|
173
|
+
|
|
174
|
+
# @!attribute [rw] tov
|
|
175
|
+
# Returns turnovers per game
|
|
176
|
+
# @api public
|
|
177
|
+
# @example
|
|
178
|
+
# stat.tov #=> 2.8
|
|
179
|
+
# @return [Float] turnovers
|
|
180
|
+
attribute :tov, Shale::Type::Float
|
|
181
|
+
|
|
182
|
+
# @!attribute [rw] pf
|
|
183
|
+
# Returns personal fouls per game
|
|
184
|
+
# @api public
|
|
185
|
+
# @example
|
|
186
|
+
# stat.pf #=> 1.8
|
|
187
|
+
# @return [Float] personal fouls
|
|
188
|
+
attribute :pf, Shale::Type::Float
|
|
189
|
+
|
|
190
|
+
# @!attribute [rw] pts
|
|
191
|
+
# Returns points per game
|
|
192
|
+
# @api public
|
|
193
|
+
# @example
|
|
194
|
+
# stat.pts #=> 26.4
|
|
195
|
+
# @return [Float] points
|
|
196
|
+
attribute :pts, Shale::Type::Float
|
|
197
|
+
|
|
198
|
+
# @!attribute [rw] eff
|
|
199
|
+
# Returns efficiency
|
|
200
|
+
# @api public
|
|
201
|
+
# @example
|
|
202
|
+
# stat.eff #=> 24.5
|
|
203
|
+
# @return [Float] efficiency
|
|
204
|
+
attribute :eff, Shale::Type::Float
|
|
205
|
+
|
|
206
|
+
# @!attribute [rw] ast_tov
|
|
207
|
+
# Returns assist to turnover ratio
|
|
208
|
+
# @api public
|
|
209
|
+
# @example
|
|
210
|
+
# stat.ast_tov #=> 2.18
|
|
211
|
+
# @return [Float] assist to turnover ratio
|
|
212
|
+
attribute :ast_tov, Shale::Type::Float
|
|
213
|
+
|
|
214
|
+
# @!attribute [rw] stl_tov
|
|
215
|
+
# Returns steal to turnover ratio
|
|
216
|
+
# @api public
|
|
217
|
+
# @example
|
|
218
|
+
# stat.stl_tov #=> 0.32
|
|
219
|
+
# @return [Float] steal to turnover ratio
|
|
220
|
+
attribute :stl_tov, Shale::Type::Float
|
|
221
|
+
|
|
222
|
+
# Returns the player object
|
|
223
|
+
#
|
|
224
|
+
# @api public
|
|
225
|
+
# @example
|
|
226
|
+
# stat.player #=> #<NBA::Player>
|
|
227
|
+
# @return [Player, nil] the player object
|
|
228
|
+
def player
|
|
229
|
+
Players.find(player_id)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Returns the full name
|
|
233
|
+
#
|
|
234
|
+
# @api public
|
|
235
|
+
# @example
|
|
236
|
+
# stat.full_name #=> "Stephen Curry"
|
|
237
|
+
# @return [String] the full name
|
|
238
|
+
def full_name
|
|
239
|
+
"#{first_name} #{last_name}".strip
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "pass_stat"
|
|
5
|
+
require_relative "utils"
|
|
6
|
+
|
|
7
|
+
module NBA
|
|
8
|
+
# Provides methods to retrieve player tracking pass statistics
|
|
9
|
+
#
|
|
10
|
+
# @api public
|
|
11
|
+
module PlayerDashPtPass
|
|
12
|
+
# Result set name for passes made
|
|
13
|
+
# @return [String] the result set name
|
|
14
|
+
PASSES_MADE = "PassesMade".freeze
|
|
15
|
+
|
|
16
|
+
# Result set name for passes received
|
|
17
|
+
# @return [String] the result set name
|
|
18
|
+
PASSES_RECEIVED = "PassesReceived".freeze
|
|
19
|
+
|
|
20
|
+
# Retrieves passes made statistics for a player
|
|
21
|
+
#
|
|
22
|
+
# @api public
|
|
23
|
+
# @example
|
|
24
|
+
# stats = NBA::PlayerDashPtPass.passes_made(player: 201939)
|
|
25
|
+
# stats.each { |s| puts "#{s.pass_to}: #{s.ast} assists" }
|
|
26
|
+
# @param player [Integer, Player] the player ID or Player object
|
|
27
|
+
# @param team [Integer, Team] the team ID or Team object
|
|
28
|
+
# @param season [Integer] the season year
|
|
29
|
+
# @param season_type [String] the season type
|
|
30
|
+
# @param per_mode [String] the per mode
|
|
31
|
+
# @param client [Client] the API client to use
|
|
32
|
+
# @return [Collection] a collection of pass statistics
|
|
33
|
+
def self.passes_made(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
|
|
34
|
+
per_mode: "PerGame", client: CLIENT)
|
|
35
|
+
options = {season_type: season_type, per_mode: per_mode, result_set: PASSES_MADE}
|
|
36
|
+
fetch_stats(player, team, season, options, client: client)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Retrieves passes received statistics for a player
|
|
40
|
+
#
|
|
41
|
+
# @api public
|
|
42
|
+
# @example
|
|
43
|
+
# stats = NBA::PlayerDashPtPass.passes_received(player: 201939)
|
|
44
|
+
# stats.each { |s| puts "#{s.pass_to}: #{s.pass} passes" }
|
|
45
|
+
# @param player [Integer, Player] the player ID or Player object
|
|
46
|
+
# @param team [Integer, Team] the team ID or Team object
|
|
47
|
+
# @param season [Integer] the season year
|
|
48
|
+
# @param season_type [String] the season type
|
|
49
|
+
# @param per_mode [String] the per mode
|
|
50
|
+
# @param client [Client] the API client to use
|
|
51
|
+
# @return [Collection] a collection of pass statistics
|
|
52
|
+
def self.passes_received(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
|
|
53
|
+
per_mode: "PerGame", client: CLIENT)
|
|
54
|
+
options = {season_type: season_type, per_mode: per_mode, result_set: PASSES_RECEIVED}
|
|
55
|
+
fetch_stats(player, team, season, options, client: client)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Fetches pass stats from the API
|
|
59
|
+
#
|
|
60
|
+
# @api private
|
|
61
|
+
# @return [Collection] collection of pass stats
|
|
62
|
+
def self.fetch_stats(player, team, season, options, client:)
|
|
63
|
+
path = build_path(player, team, season, options.fetch(:season_type), options.fetch(:per_mode))
|
|
64
|
+
response = client.get(path)
|
|
65
|
+
parse_response(response, options.fetch(:result_set))
|
|
66
|
+
end
|
|
67
|
+
private_class_method :fetch_stats
|
|
68
|
+
|
|
69
|
+
# Builds the API path
|
|
70
|
+
#
|
|
71
|
+
# @api private
|
|
72
|
+
# @return [String] the request path
|
|
73
|
+
def self.build_path(player, team, season, season_type, per_mode)
|
|
74
|
+
player_id = Utils.extract_id(player)
|
|
75
|
+
team_id = Utils.extract_id(team)
|
|
76
|
+
season_str = Utils.format_season(season)
|
|
77
|
+
"playerdashptpass?PlayerID=#{player_id}&TeamID=#{team_id}&Season=#{season_str}" \
|
|
78
|
+
"&SeasonType=#{season_type}&PerMode=#{per_mode}&LeagueID=00"
|
|
79
|
+
end
|
|
80
|
+
private_class_method :build_path
|
|
81
|
+
|
|
82
|
+
# Parses the API response into pass stat objects
|
|
83
|
+
#
|
|
84
|
+
# @api private
|
|
85
|
+
# @return [Collection] collection of pass stats
|
|
86
|
+
def self.parse_response(response, result_set_name)
|
|
87
|
+
return Collection.new if response.nil? || response.empty?
|
|
88
|
+
|
|
89
|
+
data = JSON.parse(response)
|
|
90
|
+
result_set = find_result_set(data, result_set_name)
|
|
91
|
+
build_collection(result_set)
|
|
92
|
+
end
|
|
93
|
+
private_class_method :parse_response
|
|
94
|
+
|
|
95
|
+
# Finds a result set by name
|
|
96
|
+
#
|
|
97
|
+
# @api private
|
|
98
|
+
# @return [Hash, nil] the result set hash or nil if not found
|
|
99
|
+
def self.find_result_set(data, result_set_name)
|
|
100
|
+
result_sets = data["resultSets"]
|
|
101
|
+
return unless result_sets
|
|
102
|
+
|
|
103
|
+
result_sets.find { |rs| rs["name"].eql?(result_set_name) }
|
|
104
|
+
end
|
|
105
|
+
private_class_method :find_result_set
|
|
106
|
+
|
|
107
|
+
# Builds a collection from a result set
|
|
108
|
+
#
|
|
109
|
+
# @api private
|
|
110
|
+
# @return [Collection] the stats collection
|
|
111
|
+
def self.build_collection(result_set)
|
|
112
|
+
return Collection.new unless result_set
|
|
113
|
+
|
|
114
|
+
headers = result_set["headers"]
|
|
115
|
+
rows = result_set["rowSet"]
|
|
116
|
+
return Collection.new unless headers && rows
|
|
117
|
+
|
|
118
|
+
Collection.new(rows.map { |row| build_pass_stat(headers.zip(row).to_h) })
|
|
119
|
+
end
|
|
120
|
+
private_class_method :build_collection
|
|
121
|
+
|
|
122
|
+
# Builds a pass stat from API data
|
|
123
|
+
#
|
|
124
|
+
# @api private
|
|
125
|
+
# @return [PassStat] the pass stat object
|
|
126
|
+
def self.build_pass_stat(data)
|
|
127
|
+
PassStat.new(**identity_info(data), **pass_info(data), **shooting_info(data))
|
|
128
|
+
end
|
|
129
|
+
private_class_method :build_pass_stat
|
|
130
|
+
|
|
131
|
+
# Extracts identity information from data
|
|
132
|
+
#
|
|
133
|
+
# @api private
|
|
134
|
+
# @return [Hash] the identity information hash
|
|
135
|
+
def self.identity_info(data)
|
|
136
|
+
{player_id: data["PLAYER_ID"], player_name_last_first: data["PLAYER_NAME_LAST_FIRST"],
|
|
137
|
+
team_id: data["TEAM_ID"], team_abbreviation: data["TEAM_ABBREVIATION"],
|
|
138
|
+
pass_teammate_player_id: data["PASS_TEAMMATE_PLAYER_ID"]}
|
|
139
|
+
end
|
|
140
|
+
private_class_method :identity_info
|
|
141
|
+
|
|
142
|
+
# Extracts pass information from data
|
|
143
|
+
#
|
|
144
|
+
# @api private
|
|
145
|
+
# @return [Hash] the pass information hash
|
|
146
|
+
def self.pass_info(data)
|
|
147
|
+
{pass_to: data["PASS_TO"], gp: data["GP"], g: data["G"],
|
|
148
|
+
pass_type: data["PASS_TYPE"], frequency: data["FREQUENCY"],
|
|
149
|
+
pass: data["PASS"], ast: data["AST"]}
|
|
150
|
+
end
|
|
151
|
+
private_class_method :pass_info
|
|
152
|
+
|
|
153
|
+
# Extracts shooting information from data
|
|
154
|
+
#
|
|
155
|
+
# @api private
|
|
156
|
+
# @return [Hash] the shooting information hash
|
|
157
|
+
def self.shooting_info(data)
|
|
158
|
+
{fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
|
|
159
|
+
fg2m: data["FG2M"], fg2a: data["FG2A"], fg2_pct: data["FG2_PCT"],
|
|
160
|
+
fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"]}
|
|
161
|
+
end
|
|
162
|
+
private_class_method :shooting_info
|
|
163
|
+
end
|
|
164
|
+
end
|