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,358 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "cume_stats_player_game"
|
|
5
|
+
require_relative "cume_stats_player_total"
|
|
6
|
+
require_relative "league"
|
|
7
|
+
require_relative "utils"
|
|
8
|
+
|
|
9
|
+
module NBA
|
|
10
|
+
# Provides methods to retrieve cumulative player statistics
|
|
11
|
+
module CumeStatsPlayer
|
|
12
|
+
# Result set name for game-by-game stats
|
|
13
|
+
# @return [String] the result set name
|
|
14
|
+
GAME_BY_GAME_STATS = "GameByGameStats".freeze
|
|
15
|
+
|
|
16
|
+
# Result set name for total player stats
|
|
17
|
+
# @return [String] the result set name
|
|
18
|
+
TOTAL_PLAYER_STATS = "TotalPlayerStats".freeze
|
|
19
|
+
|
|
20
|
+
# Retrieves cumulative player statistics for specific games
|
|
21
|
+
#
|
|
22
|
+
# @api public
|
|
23
|
+
# @example
|
|
24
|
+
# stats = NBA::CumeStatsPlayer.find(
|
|
25
|
+
# player: 201939,
|
|
26
|
+
# game_ids: ["0022400001", "0022400002"],
|
|
27
|
+
# season: "2024-25",
|
|
28
|
+
# season_type: "Regular Season"
|
|
29
|
+
# )
|
|
30
|
+
# stats[:game_by_game].each { |g| puts "#{g.game_date}: #{g.pts} PTS" }
|
|
31
|
+
# puts "Total: #{stats[:total].pts} PTS"
|
|
32
|
+
# @param player [Integer, Player] the player ID or Player object
|
|
33
|
+
# @param game_ids [Array<String>, String] game IDs as array or pipe-separated string
|
|
34
|
+
# @param season [String] the season (e.g., "2024-25")
|
|
35
|
+
# @param season_type [String] the season type (default "Regular Season")
|
|
36
|
+
# @param league [String, League] the league ID or League object (default NBA)
|
|
37
|
+
# @param client [Client] the API client to use
|
|
38
|
+
# @return [Hash, nil] hash with :game_by_game and :total keys, or nil
|
|
39
|
+
def self.find(player:, game_ids:, season:, season_type: "Regular Season", league: League::NBA, client: CLIENT)
|
|
40
|
+
player_id = Utils.extract_id(player)
|
|
41
|
+
league_id = Utils.extract_league_id(league)
|
|
42
|
+
game_ids_param = format_game_ids(game_ids)
|
|
43
|
+
|
|
44
|
+
path = "cumestatsplayer?PlayerID=#{player_id}&GameIDs=#{game_ids_param}" \
|
|
45
|
+
"&LeagueID=#{league_id}&Season=#{season}&SeasonType=#{season_type}"
|
|
46
|
+
response = client.get(path)
|
|
47
|
+
parse_response(response)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Parses the API response
|
|
51
|
+
#
|
|
52
|
+
# @api private
|
|
53
|
+
# @param response [String] the JSON response body
|
|
54
|
+
# @return [Hash, nil] hash with :game_by_game and :total keys, or nil
|
|
55
|
+
def self.parse_response(response)
|
|
56
|
+
return unless response
|
|
57
|
+
|
|
58
|
+
data = JSON.parse(response)
|
|
59
|
+
game_by_game = parse_game_by_game(data)
|
|
60
|
+
total = parse_total(data)
|
|
61
|
+
|
|
62
|
+
return unless game_by_game && total
|
|
63
|
+
|
|
64
|
+
{game_by_game: game_by_game, total: total}
|
|
65
|
+
end
|
|
66
|
+
private_class_method :parse_response
|
|
67
|
+
|
|
68
|
+
# Parses the game-by-game stats result set
|
|
69
|
+
#
|
|
70
|
+
# @api private
|
|
71
|
+
# @param data [Hash] the parsed JSON data
|
|
72
|
+
# @return [Collection, nil] collection of game stats, or nil
|
|
73
|
+
def self.parse_game_by_game(data)
|
|
74
|
+
result_set = find_result_set(data, GAME_BY_GAME_STATS)
|
|
75
|
+
return unless result_set
|
|
76
|
+
|
|
77
|
+
headers = result_set["headers"]
|
|
78
|
+
rows = result_set["rowSet"]
|
|
79
|
+
return unless headers && rows
|
|
80
|
+
|
|
81
|
+
games = rows.map { |row| build_game(headers, row) }
|
|
82
|
+
Collection.new(games)
|
|
83
|
+
end
|
|
84
|
+
private_class_method :parse_game_by_game
|
|
85
|
+
|
|
86
|
+
# Parses the total player stats result set
|
|
87
|
+
#
|
|
88
|
+
# @api private
|
|
89
|
+
# @param data [Hash] the parsed JSON data
|
|
90
|
+
# @return [CumeStatsPlayerTotal, nil] total stats, or nil
|
|
91
|
+
def self.parse_total(data)
|
|
92
|
+
result_set = find_result_set(data, TOTAL_PLAYER_STATS)
|
|
93
|
+
return unless result_set
|
|
94
|
+
|
|
95
|
+
headers = result_set["headers"]
|
|
96
|
+
row = result_set.dig("rowSet", 0)
|
|
97
|
+
return unless headers && row
|
|
98
|
+
|
|
99
|
+
build_total(headers, row)
|
|
100
|
+
end
|
|
101
|
+
private_class_method :parse_total
|
|
102
|
+
|
|
103
|
+
# Finds a result set by name
|
|
104
|
+
#
|
|
105
|
+
# @api private
|
|
106
|
+
# @param data [Hash] the parsed JSON data
|
|
107
|
+
# @param name [String] the result set name
|
|
108
|
+
# @return [Hash, nil] the result set
|
|
109
|
+
def self.find_result_set(data, name)
|
|
110
|
+
result_sets = data["resultSets"]
|
|
111
|
+
return unless result_sets
|
|
112
|
+
|
|
113
|
+
result_sets.find { |rs| rs["name"].eql?(name) }
|
|
114
|
+
end
|
|
115
|
+
private_class_method :find_result_set
|
|
116
|
+
|
|
117
|
+
# Builds a game stat object from a row
|
|
118
|
+
#
|
|
119
|
+
# @api private
|
|
120
|
+
# @param headers [Array<String>] the column headers
|
|
121
|
+
# @param row [Array] the row data
|
|
122
|
+
# @return [CumeStatsPlayerGame] the game stat object
|
|
123
|
+
def self.build_game(headers, row)
|
|
124
|
+
data = headers.zip(row).to_h
|
|
125
|
+
CumeStatsPlayerGame.new(**GameAttributes.extract(data))
|
|
126
|
+
end
|
|
127
|
+
private_class_method :build_game
|
|
128
|
+
|
|
129
|
+
# Builds a total stat object from a row
|
|
130
|
+
#
|
|
131
|
+
# @api private
|
|
132
|
+
# @param headers [Array<String>] the column headers
|
|
133
|
+
# @param row [Array] the row data
|
|
134
|
+
# @return [CumeStatsPlayerTotal] the total stat object
|
|
135
|
+
def self.build_total(headers, row)
|
|
136
|
+
data = headers.zip(row).to_h
|
|
137
|
+
CumeStatsPlayerTotal.new(**TotalAttributes.extract(data))
|
|
138
|
+
end
|
|
139
|
+
private_class_method :build_total
|
|
140
|
+
|
|
141
|
+
# Formats game IDs as a pipe-separated string
|
|
142
|
+
#
|
|
143
|
+
# @api private
|
|
144
|
+
# @param game_ids [Array<String>, String] game IDs as array or string
|
|
145
|
+
# @return [String] pipe-separated game IDs
|
|
146
|
+
def self.format_game_ids(game_ids)
|
|
147
|
+
game_ids.instance_of?(Array) ? game_ids.join("|") : game_ids
|
|
148
|
+
end
|
|
149
|
+
private_class_method :format_game_ids
|
|
150
|
+
|
|
151
|
+
# Extracts game attributes from row data
|
|
152
|
+
# @api private
|
|
153
|
+
module GameAttributes
|
|
154
|
+
# Extracts all game attributes from data
|
|
155
|
+
# @api private
|
|
156
|
+
# @param data [Hash] the row data
|
|
157
|
+
# @return [Hash] extracted attributes
|
|
158
|
+
def self.extract(data)
|
|
159
|
+
identity(data).merge(stats(data))
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Extracts identity attributes from data
|
|
163
|
+
# @api private
|
|
164
|
+
# @param data [Hash] the row data
|
|
165
|
+
# @return [Hash] identity attributes
|
|
166
|
+
def self.identity(data)
|
|
167
|
+
{
|
|
168
|
+
game_id: data["GAME_ID"],
|
|
169
|
+
matchup: data["MATCHUP"],
|
|
170
|
+
game_date: data["GAME_DATE"],
|
|
171
|
+
vs_team_id: data["VS_TEAM_ID"],
|
|
172
|
+
vs_team_city: data["VS_TEAM_CITY"],
|
|
173
|
+
vs_team_name: data["VS_TEAM_NAME"]
|
|
174
|
+
}
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Extracts stat attributes from data
|
|
178
|
+
# @api private
|
|
179
|
+
# @param data [Hash] the row data
|
|
180
|
+
# @return [Hash] stat attributes
|
|
181
|
+
def self.stats(data)
|
|
182
|
+
time(data).merge(shooting(data)).merge(rebounds(data)).merge(other(data))
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Extracts time attributes from data
|
|
186
|
+
# @api private
|
|
187
|
+
# @param data [Hash] the row data
|
|
188
|
+
# @return [Hash] time attributes
|
|
189
|
+
def self.time(data)
|
|
190
|
+
{min: data["MIN"], sec: data["SEC"]}
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Extracts shooting attributes from data
|
|
194
|
+
# @api private
|
|
195
|
+
# @param data [Hash] the row data
|
|
196
|
+
# @return [Hash] shooting attributes
|
|
197
|
+
def self.shooting(data)
|
|
198
|
+
{
|
|
199
|
+
fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
|
|
200
|
+
fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"],
|
|
201
|
+
ftm: data["FTM"], fta: data["FTA"], ft_pct: data["FT_PCT"]
|
|
202
|
+
}
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Extracts rebound attributes from data
|
|
206
|
+
# @api private
|
|
207
|
+
# @param data [Hash] the row data
|
|
208
|
+
# @return [Hash] rebound attributes
|
|
209
|
+
def self.rebounds(data)
|
|
210
|
+
{oreb: data["OREB"], dreb: data["DREB"], reb: data["REB"]}
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Extracts other stat attributes from data
|
|
214
|
+
# @api private
|
|
215
|
+
# @param data [Hash] the row data
|
|
216
|
+
# @return [Hash] other stat attributes
|
|
217
|
+
def self.other(data)
|
|
218
|
+
{
|
|
219
|
+
ast: data["AST"], pf: data["PF"], stl: data["STL"],
|
|
220
|
+
tov: data["TOV"], blk: data["BLK"], pts: data["PTS"]
|
|
221
|
+
}
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Extracts total attributes from row data
|
|
226
|
+
# @api private
|
|
227
|
+
module TotalAttributes
|
|
228
|
+
# Extracts all total attributes from data
|
|
229
|
+
# @api private
|
|
230
|
+
# @param data [Hash] the row data
|
|
231
|
+
# @return [Hash] extracted attributes
|
|
232
|
+
def self.extract(data)
|
|
233
|
+
identity(data).merge(totals(data)).merge(averages(data)).merge(maximums(data))
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Extracts identity attributes from data
|
|
237
|
+
# @api private
|
|
238
|
+
# @param data [Hash] the row data
|
|
239
|
+
# @return [Hash] identity attributes
|
|
240
|
+
def self.identity(data)
|
|
241
|
+
{
|
|
242
|
+
player_id: data["PLAYER_ID"], player_name: data["PLAYER_NAME"],
|
|
243
|
+
jersey_num: data["JERSEY_NUM"], season: data["SEASON"],
|
|
244
|
+
gp: data["GP"], gs: data["GS"],
|
|
245
|
+
actual_minutes: data["ACTUAL_MINUTES"], actual_seconds: data["ACTUAL_SECONDS"]
|
|
246
|
+
}
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Extracts total stat attributes from data
|
|
250
|
+
# @api private
|
|
251
|
+
# @param data [Hash] the row data
|
|
252
|
+
# @return [Hash] total stat attributes
|
|
253
|
+
def self.totals(data)
|
|
254
|
+
shooting(data).merge(rebounds_and_other(data))
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Extracts shooting attributes from data
|
|
258
|
+
# @api private
|
|
259
|
+
# @param data [Hash] the row data
|
|
260
|
+
# @return [Hash] shooting attributes
|
|
261
|
+
def self.shooting(data)
|
|
262
|
+
{
|
|
263
|
+
fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
|
|
264
|
+
fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"],
|
|
265
|
+
ftm: data["FTM"], fta: data["FTA"], ft_pct: data["FT_PCT"]
|
|
266
|
+
}
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Extracts rebound and other stat attributes from data
|
|
270
|
+
# @api private
|
|
271
|
+
# @param data [Hash] the row data
|
|
272
|
+
# @return [Hash] rebound and other stat attributes
|
|
273
|
+
def self.rebounds_and_other(data)
|
|
274
|
+
{
|
|
275
|
+
oreb: data["OREB"], dreb: data["DREB"], tot_reb: data["TOT_REB"],
|
|
276
|
+
ast: data["AST"], pf: data["PF"], stl: data["STL"],
|
|
277
|
+
tov: data["TOV"], blk: data["BLK"], pts: data["PTS"]
|
|
278
|
+
}
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Extracts average stat attributes from data
|
|
282
|
+
# @api private
|
|
283
|
+
# @param data [Hash] the row data
|
|
284
|
+
# @return [Hash] average stat attributes
|
|
285
|
+
def self.averages(data)
|
|
286
|
+
avg_time(data).merge(avg_shooting(data)).merge(avg_other(data))
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Extracts average time attributes from data
|
|
290
|
+
# @api private
|
|
291
|
+
# @param data [Hash] the row data
|
|
292
|
+
# @return [Hash] average time attributes
|
|
293
|
+
def self.avg_time(data)
|
|
294
|
+
{avg_min: data["AVG_MIN"], avg_sec: data["AVG_SEC"]}
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Extracts average shooting attributes from data
|
|
298
|
+
# @api private
|
|
299
|
+
# @param data [Hash] the row data
|
|
300
|
+
# @return [Hash] average shooting attributes
|
|
301
|
+
def self.avg_shooting(data)
|
|
302
|
+
{
|
|
303
|
+
avg_fgm: data["AVG_FGM"], avg_fga: data["AVG_FGA"],
|
|
304
|
+
avg_fg3m: data["AVG_FG3M"], avg_fg3a: data["AVG_FG3A"],
|
|
305
|
+
avg_ftm: data["AVG_FTM"], avg_fta: data["AVG_FTA"],
|
|
306
|
+
avg_oreb: data["AVG_OREB"], avg_dreb: data["AVG_DREB"]
|
|
307
|
+
}
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Extracts average other stat attributes from data
|
|
311
|
+
# @api private
|
|
312
|
+
# @param data [Hash] the row data
|
|
313
|
+
# @return [Hash] average other stat attributes
|
|
314
|
+
def self.avg_other(data)
|
|
315
|
+
{
|
|
316
|
+
avg_tot_reb: data["AVG_TOT_REB"], avg_ast: data["AVG_AST"],
|
|
317
|
+
avg_pf: data["AVG_PF"], avg_stl: data["AVG_STL"],
|
|
318
|
+
avg_tov: data["AVG_TOV"], avg_blk: data["AVG_BLK"],
|
|
319
|
+
avg_pts: data["AVG_PTS"]
|
|
320
|
+
}
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Extracts maximum stat attributes from data
|
|
324
|
+
# @api private
|
|
325
|
+
# @param data [Hash] the row data
|
|
326
|
+
# @return [Hash] maximum stat attributes
|
|
327
|
+
def self.maximums(data)
|
|
328
|
+
max_shooting(data).merge(max_other(data))
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# Extracts maximum shooting attributes from data
|
|
332
|
+
# @api private
|
|
333
|
+
# @param data [Hash] the row data
|
|
334
|
+
# @return [Hash] maximum shooting attributes
|
|
335
|
+
def self.max_shooting(data)
|
|
336
|
+
{
|
|
337
|
+
max_min: data["MAX_MIN"], max_fgm: data["MAX_FGM"],
|
|
338
|
+
max_fga: data["MAX_FGA"], max_fg3m: data["MAX_FG3M"],
|
|
339
|
+
max_fg3a: data["MAX_FG3A"], max_ftm: data["MAX_FTM"],
|
|
340
|
+
max_fta: data["MAX_FTA"], max_oreb: data["MAX_OREB"],
|
|
341
|
+
max_dreb: data["MAX_DREB"], max_reb: data["MAX_REB"]
|
|
342
|
+
}
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# Extracts maximum other stat attributes from data
|
|
346
|
+
# @api private
|
|
347
|
+
# @param data [Hash] the row data
|
|
348
|
+
# @return [Hash] maximum other stat attributes
|
|
349
|
+
def self.max_other(data)
|
|
350
|
+
{
|
|
351
|
+
max_ast: data["MAX_AST"], max_pf: data["MAX_PF"],
|
|
352
|
+
max_stl: data["MAX_STL"], max_tov: data["MAX_TOV"],
|
|
353
|
+
max_blk: data["MAX_BLK"], max_pts: data["MAX_PTS"]
|
|
354
|
+
}
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
require "equalizer"
|
|
2
|
+
require "shale"
|
|
3
|
+
|
|
4
|
+
module NBA
|
|
5
|
+
# Represents a single game in cumulative player statistics
|
|
6
|
+
class CumeStatsPlayerGame < Shale::Mapper
|
|
7
|
+
include Equalizer.new(:game_id)
|
|
8
|
+
|
|
9
|
+
# @!attribute [rw] game_id
|
|
10
|
+
# Returns the game ID
|
|
11
|
+
# @api public
|
|
12
|
+
# @example
|
|
13
|
+
# game.game_id #=> "0022400001"
|
|
14
|
+
# @return [String] the game ID
|
|
15
|
+
attribute :game_id, Shale::Type::String
|
|
16
|
+
|
|
17
|
+
# @!attribute [rw] matchup
|
|
18
|
+
# Returns the matchup description
|
|
19
|
+
# @api public
|
|
20
|
+
# @example
|
|
21
|
+
# game.matchup #=> "GSW vs. LAL"
|
|
22
|
+
# @return [String] the matchup description
|
|
23
|
+
attribute :matchup, Shale::Type::String
|
|
24
|
+
|
|
25
|
+
# @!attribute [rw] game_date
|
|
26
|
+
# Returns the game date
|
|
27
|
+
# @api public
|
|
28
|
+
# @example
|
|
29
|
+
# game.game_date #=> "2024-10-22"
|
|
30
|
+
# @return [String] the game date
|
|
31
|
+
attribute :game_date, Shale::Type::String
|
|
32
|
+
|
|
33
|
+
# @!attribute [rw] vs_team_id
|
|
34
|
+
# Returns the opposing team ID
|
|
35
|
+
# @api public
|
|
36
|
+
# @example
|
|
37
|
+
# game.vs_team_id #=> 1610612747
|
|
38
|
+
# @return [Integer] the opposing team ID
|
|
39
|
+
attribute :vs_team_id, Shale::Type::Integer
|
|
40
|
+
|
|
41
|
+
# @!attribute [rw] vs_team_city
|
|
42
|
+
# Returns the opposing team city
|
|
43
|
+
# @api public
|
|
44
|
+
# @example
|
|
45
|
+
# game.vs_team_city #=> "Los Angeles"
|
|
46
|
+
# @return [String] the opposing team city
|
|
47
|
+
attribute :vs_team_city, Shale::Type::String
|
|
48
|
+
|
|
49
|
+
# @!attribute [rw] vs_team_name
|
|
50
|
+
# Returns the opposing team name
|
|
51
|
+
# @api public
|
|
52
|
+
# @example
|
|
53
|
+
# game.vs_team_name #=> "Lakers"
|
|
54
|
+
# @return [String] the opposing team name
|
|
55
|
+
attribute :vs_team_name, Shale::Type::String
|
|
56
|
+
|
|
57
|
+
# @!attribute [rw] min
|
|
58
|
+
# Returns the minutes played
|
|
59
|
+
# @api public
|
|
60
|
+
# @example
|
|
61
|
+
# game.min #=> 35
|
|
62
|
+
# @return [Integer] the minutes played
|
|
63
|
+
attribute :min, Shale::Type::Integer
|
|
64
|
+
|
|
65
|
+
# @!attribute [rw] sec
|
|
66
|
+
# Returns the seconds played
|
|
67
|
+
# @api public
|
|
68
|
+
# @example
|
|
69
|
+
# game.sec #=> 42
|
|
70
|
+
# @return [Integer] the seconds played
|
|
71
|
+
attribute :sec, Shale::Type::Integer
|
|
72
|
+
|
|
73
|
+
# @!attribute [rw] fgm
|
|
74
|
+
# Returns the field goals made
|
|
75
|
+
# @api public
|
|
76
|
+
# @example
|
|
77
|
+
# game.fgm #=> 10
|
|
78
|
+
# @return [Integer] the field goals made
|
|
79
|
+
attribute :fgm, Shale::Type::Integer
|
|
80
|
+
|
|
81
|
+
# @!attribute [rw] fga
|
|
82
|
+
# Returns the field goals attempted
|
|
83
|
+
# @api public
|
|
84
|
+
# @example
|
|
85
|
+
# game.fga #=> 20
|
|
86
|
+
# @return [Integer] the field goals attempted
|
|
87
|
+
attribute :fga, Shale::Type::Integer
|
|
88
|
+
|
|
89
|
+
# @!attribute [rw] fg_pct
|
|
90
|
+
# Returns the field goal percentage
|
|
91
|
+
# @api public
|
|
92
|
+
# @example
|
|
93
|
+
# game.fg_pct #=> 0.500
|
|
94
|
+
# @return [Float] the field goal percentage
|
|
95
|
+
attribute :fg_pct, Shale::Type::Float
|
|
96
|
+
|
|
97
|
+
# @!attribute [rw] fg3m
|
|
98
|
+
# Returns the three-point field goals made
|
|
99
|
+
# @api public
|
|
100
|
+
# @example
|
|
101
|
+
# game.fg3m #=> 3
|
|
102
|
+
# @return [Integer] the three-point field goals made
|
|
103
|
+
attribute :fg3m, Shale::Type::Integer
|
|
104
|
+
|
|
105
|
+
# @!attribute [rw] fg3a
|
|
106
|
+
# Returns the three-point field goals attempted
|
|
107
|
+
# @api public
|
|
108
|
+
# @example
|
|
109
|
+
# game.fg3a #=> 8
|
|
110
|
+
# @return [Integer] the three-point field goals attempted
|
|
111
|
+
attribute :fg3a, Shale::Type::Integer
|
|
112
|
+
|
|
113
|
+
# @!attribute [rw] fg3_pct
|
|
114
|
+
# Returns the three-point field goal percentage
|
|
115
|
+
# @api public
|
|
116
|
+
# @example
|
|
117
|
+
# game.fg3_pct #=> 0.375
|
|
118
|
+
# @return [Float] the three-point field goal percentage
|
|
119
|
+
attribute :fg3_pct, Shale::Type::Float
|
|
120
|
+
|
|
121
|
+
# @!attribute [rw] ftm
|
|
122
|
+
# Returns the free throws made
|
|
123
|
+
# @api public
|
|
124
|
+
# @example
|
|
125
|
+
# game.ftm #=> 7
|
|
126
|
+
# @return [Integer] the free throws made
|
|
127
|
+
attribute :ftm, Shale::Type::Integer
|
|
128
|
+
|
|
129
|
+
# @!attribute [rw] fta
|
|
130
|
+
# Returns the free throws attempted
|
|
131
|
+
# @api public
|
|
132
|
+
# @example
|
|
133
|
+
# game.fta #=> 8
|
|
134
|
+
# @return [Integer] the free throws attempted
|
|
135
|
+
attribute :fta, Shale::Type::Integer
|
|
136
|
+
|
|
137
|
+
# @!attribute [rw] ft_pct
|
|
138
|
+
# Returns the free throw percentage
|
|
139
|
+
# @api public
|
|
140
|
+
# @example
|
|
141
|
+
# game.ft_pct #=> 0.875
|
|
142
|
+
# @return [Float] the free throw percentage
|
|
143
|
+
attribute :ft_pct, Shale::Type::Float
|
|
144
|
+
|
|
145
|
+
# @!attribute [rw] oreb
|
|
146
|
+
# Returns the offensive rebounds
|
|
147
|
+
# @api public
|
|
148
|
+
# @example
|
|
149
|
+
# game.oreb #=> 2
|
|
150
|
+
# @return [Integer] the offensive rebounds
|
|
151
|
+
attribute :oreb, Shale::Type::Integer
|
|
152
|
+
|
|
153
|
+
# @!attribute [rw] dreb
|
|
154
|
+
# Returns the defensive rebounds
|
|
155
|
+
# @api public
|
|
156
|
+
# @example
|
|
157
|
+
# game.dreb #=> 6
|
|
158
|
+
# @return [Integer] the defensive rebounds
|
|
159
|
+
attribute :dreb, Shale::Type::Integer
|
|
160
|
+
|
|
161
|
+
# @!attribute [rw] reb
|
|
162
|
+
# Returns the total rebounds
|
|
163
|
+
# @api public
|
|
164
|
+
# @example
|
|
165
|
+
# game.reb #=> 8
|
|
166
|
+
# @return [Integer] the total rebounds
|
|
167
|
+
attribute :reb, Shale::Type::Integer
|
|
168
|
+
|
|
169
|
+
# @!attribute [rw] ast
|
|
170
|
+
# Returns the assists
|
|
171
|
+
# @api public
|
|
172
|
+
# @example
|
|
173
|
+
# game.ast #=> 5
|
|
174
|
+
# @return [Integer] the assists
|
|
175
|
+
attribute :ast, Shale::Type::Integer
|
|
176
|
+
|
|
177
|
+
# @!attribute [rw] pf
|
|
178
|
+
# Returns the personal fouls
|
|
179
|
+
# @api public
|
|
180
|
+
# @example
|
|
181
|
+
# game.pf #=> 3
|
|
182
|
+
# @return [Integer] the personal fouls
|
|
183
|
+
attribute :pf, Shale::Type::Integer
|
|
184
|
+
|
|
185
|
+
# @!attribute [rw] stl
|
|
186
|
+
# Returns the steals
|
|
187
|
+
# @api public
|
|
188
|
+
# @example
|
|
189
|
+
# game.stl #=> 2
|
|
190
|
+
# @return [Integer] the steals
|
|
191
|
+
attribute :stl, Shale::Type::Integer
|
|
192
|
+
|
|
193
|
+
# @!attribute [rw] tov
|
|
194
|
+
# Returns the turnovers
|
|
195
|
+
# @api public
|
|
196
|
+
# @example
|
|
197
|
+
# game.tov #=> 3
|
|
198
|
+
# @return [Integer] the turnovers
|
|
199
|
+
attribute :tov, Shale::Type::Integer
|
|
200
|
+
|
|
201
|
+
# @!attribute [rw] blk
|
|
202
|
+
# Returns the blocks
|
|
203
|
+
# @api public
|
|
204
|
+
# @example
|
|
205
|
+
# game.blk #=> 1
|
|
206
|
+
# @return [Integer] the blocks
|
|
207
|
+
attribute :blk, Shale::Type::Integer
|
|
208
|
+
|
|
209
|
+
# @!attribute [rw] pts
|
|
210
|
+
# Returns the points
|
|
211
|
+
# @api public
|
|
212
|
+
# @example
|
|
213
|
+
# game.pts #=> 30
|
|
214
|
+
# @return [Integer] the points
|
|
215
|
+
attribute :pts, Shale::Type::Integer
|
|
216
|
+
end
|
|
217
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
require_relative "client"
|
|
2
|
+
require_relative "response_parser"
|
|
3
|
+
require_relative "cume_stats_player_games_entry"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
|
|
6
|
+
module NBA
|
|
7
|
+
# Provides methods to retrieve cumulative stats player games
|
|
8
|
+
#
|
|
9
|
+
# @api public
|
|
10
|
+
module CumeStatsPlayerGames
|
|
11
|
+
# Result set name for cumulative stats player games
|
|
12
|
+
# @return [String] the result set name
|
|
13
|
+
RESULTS = "CumeStatsPlayerGames".freeze
|
|
14
|
+
|
|
15
|
+
# Retrieves all cumulative stats player games for specified criteria
|
|
16
|
+
#
|
|
17
|
+
# @api public
|
|
18
|
+
# @example
|
|
19
|
+
# games = NBA::CumeStatsPlayerGames.all(player: 201939, season: 2024, season_type: "Regular Season")
|
|
20
|
+
# games.each { |game| puts "#{game.matchup} - #{game.game_id}" }
|
|
21
|
+
# @param player [Integer, Player] the player ID or Player object
|
|
22
|
+
# @param season [Integer] the season year
|
|
23
|
+
# @param season_type [String] the season type (Regular Season, Playoffs)
|
|
24
|
+
# @param league [String, League] the league ID or League object (default NBA)
|
|
25
|
+
# @param location [String, nil] filter by location (Home, Road)
|
|
26
|
+
# @param outcome [String, nil] filter by outcome (W, L)
|
|
27
|
+
# @param vs_conference [String, nil] filter by opponent conference
|
|
28
|
+
# @param vs_division [String, nil] filter by opponent division
|
|
29
|
+
# @param vs_team [Integer, Team, nil] filter by opponent team ID or Team object
|
|
30
|
+
# @param client [Client] the API client to use
|
|
31
|
+
# @return [Collection] a collection of cumulative stats player games entries
|
|
32
|
+
def self.all(player:, season:, season_type: "Regular Season", league: League::NBA, location: nil,
|
|
33
|
+
outcome: nil, vs_conference: nil, vs_division: nil, vs_team: nil, client: CLIENT)
|
|
34
|
+
opts = {player: player, season: season, season_type: season_type, league: league,
|
|
35
|
+
location: location, outcome: outcome, vs_conference: vs_conference,
|
|
36
|
+
vs_division: vs_division, vs_team: vs_team}
|
|
37
|
+
path = PathBuilder.build(opts)
|
|
38
|
+
ResponseParser.parse(client.get(path), result_set: RESULTS) { |data| build_entry(data) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Builds an entry from API data
|
|
42
|
+
#
|
|
43
|
+
# @api private
|
|
44
|
+
# @return [CumeStatsPlayerGamesEntry]
|
|
45
|
+
def self.build_entry(data)
|
|
46
|
+
CumeStatsPlayerGamesEntry.new(**entry_attributes(data))
|
|
47
|
+
end
|
|
48
|
+
private_class_method :build_entry
|
|
49
|
+
|
|
50
|
+
# Extracts entry attributes from data
|
|
51
|
+
#
|
|
52
|
+
# @api private
|
|
53
|
+
# @param data [Hash] the entry data
|
|
54
|
+
# @return [Hash] the entry attributes
|
|
55
|
+
def self.entry_attributes(data)
|
|
56
|
+
{game_id: data["GAME_ID"], matchup: data["MATCHUP"]}
|
|
57
|
+
end
|
|
58
|
+
private_class_method :entry_attributes
|
|
59
|
+
|
|
60
|
+
# Builds API path from options
|
|
61
|
+
# @api private
|
|
62
|
+
module PathBuilder
|
|
63
|
+
# Builds the complete API path from options
|
|
64
|
+
# @api private
|
|
65
|
+
# @param opts [Hash] the options hash
|
|
66
|
+
# @return [String] the complete API path
|
|
67
|
+
def self.build(opts)
|
|
68
|
+
base_path(opts) + optional_params(opts)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Builds the base API path from options
|
|
72
|
+
# @api private
|
|
73
|
+
# @param opts [Hash] the options hash
|
|
74
|
+
# @return [String] the base API path
|
|
75
|
+
def self.base_path(opts)
|
|
76
|
+
player_id = Utils.extract_id(opts.fetch(:player))
|
|
77
|
+
league_id = Utils.extract_league_id(opts.fetch(:league))
|
|
78
|
+
season_str = Utils.format_season(opts.fetch(:season))
|
|
79
|
+
|
|
80
|
+
"cumestatsplayergames?PlayerID=#{player_id}&LeagueID=#{league_id}" \
|
|
81
|
+
"&Season=#{season_str}&SeasonType=#{opts.fetch(:season_type)}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Builds optional parameters string from options
|
|
85
|
+
# @api private
|
|
86
|
+
# @param opts [Hash] the options hash
|
|
87
|
+
# @return [String] the optional parameters string
|
|
88
|
+
def self.optional_params(opts)
|
|
89
|
+
path = ""
|
|
90
|
+
path += "&Location=#{opts.fetch(:location)}" if opts.fetch(:location)
|
|
91
|
+
path += "&Outcome=#{opts.fetch(:outcome)}" if opts.fetch(:outcome)
|
|
92
|
+
path += "&VsConference=#{opts.fetch(:vs_conference)}" if opts.fetch(:vs_conference)
|
|
93
|
+
path += "&VsDivision=#{opts.fetch(:vs_division)}" if opts.fetch(:vs_division)
|
|
94
|
+
path += "&VsTeamID=#{Utils.extract_id(opts.fetch(:vs_team))}" if opts.fetch(:vs_team)
|
|
95
|
+
path
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "equalizer"
|
|
2
|
+
require "shale"
|
|
3
|
+
|
|
4
|
+
module NBA
|
|
5
|
+
# Represents a single game entry from cumulative stats player games
|
|
6
|
+
class CumeStatsPlayerGamesEntry < Shale::Mapper
|
|
7
|
+
include Equalizer.new(:game_id)
|
|
8
|
+
|
|
9
|
+
# @!attribute [rw] game_id
|
|
10
|
+
# Returns the game ID
|
|
11
|
+
# @api public
|
|
12
|
+
# @example
|
|
13
|
+
# entry.game_id #=> "0022400001"
|
|
14
|
+
# @return [String] the game ID
|
|
15
|
+
attribute :game_id, Shale::Type::String
|
|
16
|
+
|
|
17
|
+
# @!attribute [rw] matchup
|
|
18
|
+
# Returns the game matchup description
|
|
19
|
+
# @api public
|
|
20
|
+
# @example
|
|
21
|
+
# entry.matchup #=> "GSW vs. LAL"
|
|
22
|
+
# @return [String] the matchup description
|
|
23
|
+
attribute :matchup, Shale::Type::String
|
|
24
|
+
end
|
|
25
|
+
end
|