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,99 @@
|
|
|
1
|
+
require "shale"
|
|
2
|
+
require "equalizer"
|
|
3
|
+
|
|
4
|
+
module NBA
|
|
5
|
+
# Represents a home page leader entry
|
|
6
|
+
#
|
|
7
|
+
# @api public
|
|
8
|
+
# @example
|
|
9
|
+
# leader.rank #=> 1
|
|
10
|
+
# leader.player #=> "Stephen Curry"
|
|
11
|
+
# leader.pts #=> 26.4
|
|
12
|
+
class HomePageLeader < Shale::Mapper
|
|
13
|
+
include Equalizer.new(:player_id, :team_id, :rank)
|
|
14
|
+
|
|
15
|
+
# Returns the rank
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# leader.rank #=> 1
|
|
19
|
+
# @return [Integer, nil] the rank
|
|
20
|
+
attribute :rank, Shale::Type::Integer
|
|
21
|
+
|
|
22
|
+
# Returns the player ID
|
|
23
|
+
# @api public
|
|
24
|
+
# @example
|
|
25
|
+
# leader.player_id #=> 201939
|
|
26
|
+
# @return [Integer, nil] the player ID
|
|
27
|
+
attribute :player_id, Shale::Type::Integer
|
|
28
|
+
|
|
29
|
+
# Returns the player name
|
|
30
|
+
# @api public
|
|
31
|
+
# @example
|
|
32
|
+
# leader.player #=> "Stephen Curry"
|
|
33
|
+
# @return [String, nil] the player name
|
|
34
|
+
attribute :player, Shale::Type::String
|
|
35
|
+
|
|
36
|
+
# Returns the team ID
|
|
37
|
+
# @api public
|
|
38
|
+
# @example
|
|
39
|
+
# leader.team_id #=> 1610612744
|
|
40
|
+
# @return [Integer, nil] the team ID
|
|
41
|
+
attribute :team_id, Shale::Type::Integer
|
|
42
|
+
|
|
43
|
+
# Returns the team abbreviation
|
|
44
|
+
# @api public
|
|
45
|
+
# @example
|
|
46
|
+
# leader.team_abbreviation #=> "GSW"
|
|
47
|
+
# @return [String, nil] the team abbreviation
|
|
48
|
+
attribute :team_abbreviation, Shale::Type::String
|
|
49
|
+
|
|
50
|
+
# Returns points
|
|
51
|
+
# @api public
|
|
52
|
+
# @example
|
|
53
|
+
# leader.pts #=> 26.4
|
|
54
|
+
# @return [Float, nil] points
|
|
55
|
+
attribute :pts, Shale::Type::Float
|
|
56
|
+
|
|
57
|
+
# Returns field goal percentage
|
|
58
|
+
# @api public
|
|
59
|
+
# @example
|
|
60
|
+
# leader.fg_pct #=> 0.493
|
|
61
|
+
# @return [Float, nil] field goal percentage
|
|
62
|
+
attribute :fg_pct, Shale::Type::Float
|
|
63
|
+
|
|
64
|
+
# Returns three-point percentage
|
|
65
|
+
# @api public
|
|
66
|
+
# @example
|
|
67
|
+
# leader.fg3_pct #=> 0.423
|
|
68
|
+
# @return [Float, nil] three-point percentage
|
|
69
|
+
attribute :fg3_pct, Shale::Type::Float
|
|
70
|
+
|
|
71
|
+
# Returns free throw percentage
|
|
72
|
+
# @api public
|
|
73
|
+
# @example
|
|
74
|
+
# leader.ft_pct #=> 0.913
|
|
75
|
+
# @return [Float, nil] free throw percentage
|
|
76
|
+
attribute :ft_pct, Shale::Type::Float
|
|
77
|
+
|
|
78
|
+
# Returns efficiency rating
|
|
79
|
+
# @api public
|
|
80
|
+
# @example
|
|
81
|
+
# leader.eff #=> 31.5
|
|
82
|
+
# @return [Float, nil] efficiency rating
|
|
83
|
+
attribute :eff, Shale::Type::Float
|
|
84
|
+
|
|
85
|
+
# Returns assists
|
|
86
|
+
# @api public
|
|
87
|
+
# @example
|
|
88
|
+
# leader.ast #=> 6.1
|
|
89
|
+
# @return [Float, nil] assists
|
|
90
|
+
attribute :ast, Shale::Type::Float
|
|
91
|
+
|
|
92
|
+
# Returns rebounds
|
|
93
|
+
# @api public
|
|
94
|
+
# @example
|
|
95
|
+
# leader.reb #=> 5.2
|
|
96
|
+
# @return [Float, nil] rebounds
|
|
97
|
+
attribute :reb, Shale::Type::Float
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "home_page_leader"
|
|
5
|
+
require_relative "league"
|
|
6
|
+
require_relative "response_parser"
|
|
7
|
+
require_relative "utils"
|
|
8
|
+
|
|
9
|
+
module NBA
|
|
10
|
+
# Provides methods to retrieve NBA home page leaders
|
|
11
|
+
module HomePageLeaders
|
|
12
|
+
# Result set name for home page leaders
|
|
13
|
+
# @return [String] the result set name
|
|
14
|
+
RESULT_SET = "HomePageLeaders".freeze
|
|
15
|
+
|
|
16
|
+
# Retrieves home page leaders for a season
|
|
17
|
+
#
|
|
18
|
+
# @api public
|
|
19
|
+
# @example
|
|
20
|
+
# leaders = NBA::HomePageLeaders.all(season: 2023, stat_category: "PTS")
|
|
21
|
+
# leaders.each { |l| puts "#{l.rank}. #{l.player}: #{l.pts}" }
|
|
22
|
+
# @param season [Integer] the season year
|
|
23
|
+
# @param season_type [String] the season type
|
|
24
|
+
# @param stat_category [String] the stat category (PTS, AST, REB, etc.)
|
|
25
|
+
# @param game_scope [String] the game scope (Season, Yesterday, etc.)
|
|
26
|
+
# @param player_or_team [String] player or team (Player, Team)
|
|
27
|
+
# @param player_scope [String] the player scope (All Players, Rookies)
|
|
28
|
+
# @param league [String, League] the league ID or League object
|
|
29
|
+
# @param client [Client] the API client to use
|
|
30
|
+
# @return [Collection] a collection of leaders
|
|
31
|
+
def self.all(season: Utils.current_season, season_type: "Regular Season", stat_category: "PTS",
|
|
32
|
+
game_scope: "Season", player_or_team: "Player", player_scope: "All Players",
|
|
33
|
+
league: League::NBA, client: CLIENT)
|
|
34
|
+
league_id = Utils.extract_league_id(league)
|
|
35
|
+
opts = {season: season, season_type: season_type, stat_category: stat_category,
|
|
36
|
+
game_scope: game_scope, player_or_team: player_or_team, player_scope: player_scope,
|
|
37
|
+
league_id: league_id}
|
|
38
|
+
ResponseParser.parse(client.get(build_path(opts)), result_set: RESULT_SET) { |data| build_leader(data) }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Builds the API request path
|
|
42
|
+
# @api private
|
|
43
|
+
# @return [String] the request path
|
|
44
|
+
def self.build_path(opts)
|
|
45
|
+
"homepageleaders?GameScope=#{opts[:game_scope]}&LeagueID=#{opts[:league_id]}" \
|
|
46
|
+
"&PlayerOrTeam=#{opts[:player_or_team]}&PlayerScope=#{opts[:player_scope]}" \
|
|
47
|
+
"&Season=#{Utils.format_season(opts[:season])}&SeasonType=#{opts[:season_type]}" \
|
|
48
|
+
"&StatCategory=#{opts[:stat_category]}"
|
|
49
|
+
end
|
|
50
|
+
private_class_method :build_path
|
|
51
|
+
|
|
52
|
+
# Builds a HomePageLeader object from raw data
|
|
53
|
+
# @api private
|
|
54
|
+
# @param data [Hash] the row data
|
|
55
|
+
# @return [HomePageLeader] the leader object
|
|
56
|
+
def self.build_leader(data)
|
|
57
|
+
HomePageLeader.new(**leader_attributes(data))
|
|
58
|
+
end
|
|
59
|
+
private_class_method :build_leader
|
|
60
|
+
|
|
61
|
+
# Extracts leader attributes from data
|
|
62
|
+
# @api private
|
|
63
|
+
# @param data [Hash] the row data
|
|
64
|
+
# @return [Hash] leader attributes
|
|
65
|
+
def self.leader_attributes(data)
|
|
66
|
+
{rank: data["RANK"], player_id: data["PLAYER_ID"],
|
|
67
|
+
player: data["PLAYER"], team_id: data["TEAM_ID"],
|
|
68
|
+
team_abbreviation: data["TEAM_ABBREVIATION"],
|
|
69
|
+
pts: data["PTS"], fg_pct: data["FG_PCT"],
|
|
70
|
+
fg3_pct: data["FG3_PCT"], ft_pct: data["FT_PCT"],
|
|
71
|
+
eff: data["EFF"], ast: data["AST"], reb: data["REB"]}
|
|
72
|
+
end
|
|
73
|
+
private_class_method :leader_attributes
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require "equalizer"
|
|
2
|
+
require "shale"
|
|
3
|
+
|
|
4
|
+
module NBA
|
|
5
|
+
# Represents a home page statistic entry
|
|
6
|
+
#
|
|
7
|
+
# @api public
|
|
8
|
+
# @example
|
|
9
|
+
# stat.rank #=> 1
|
|
10
|
+
# stat.team_abbreviation #=> "BOS"
|
|
11
|
+
# stat.value #=> 120.5
|
|
12
|
+
class HomePageStat < Shale::Mapper
|
|
13
|
+
include Equalizer.new(:rank, :team_id)
|
|
14
|
+
|
|
15
|
+
# Returns the rank
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# stat.rank #=> 1
|
|
19
|
+
# @return [Integer, nil] the rank
|
|
20
|
+
attribute :rank, Shale::Type::Integer
|
|
21
|
+
|
|
22
|
+
# Returns the team ID
|
|
23
|
+
# @api public
|
|
24
|
+
# @example
|
|
25
|
+
# stat.team_id #=> 1610612738
|
|
26
|
+
# @return [Integer, nil] the team ID
|
|
27
|
+
attribute :team_id, Shale::Type::Integer
|
|
28
|
+
|
|
29
|
+
# Returns the team abbreviation
|
|
30
|
+
# @api public
|
|
31
|
+
# @example
|
|
32
|
+
# stat.team_abbreviation #=> "BOS"
|
|
33
|
+
# @return [String, nil] the team abbreviation
|
|
34
|
+
attribute :team_abbreviation, Shale::Type::String
|
|
35
|
+
|
|
36
|
+
# Returns the team name
|
|
37
|
+
# @api public
|
|
38
|
+
# @example
|
|
39
|
+
# stat.team_name #=> "Boston Celtics"
|
|
40
|
+
# @return [String, nil] the team name
|
|
41
|
+
attribute :team_name, Shale::Type::String
|
|
42
|
+
|
|
43
|
+
# Returns the statistic value
|
|
44
|
+
# @api public
|
|
45
|
+
# @example
|
|
46
|
+
# stat.value #=> 120.5
|
|
47
|
+
# @return [Float, nil] the statistic value
|
|
48
|
+
attribute :value, Shale::Type::Float
|
|
49
|
+
|
|
50
|
+
# Returns the statistic name
|
|
51
|
+
# @api public
|
|
52
|
+
# @example
|
|
53
|
+
# stat.stat_name #=> "pts"
|
|
54
|
+
# @return [String, nil] the statistic name
|
|
55
|
+
attribute :stat_name, Shale::Type::String
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "home_page_stat"
|
|
5
|
+
require_relative "league"
|
|
6
|
+
require_relative "response_parser"
|
|
7
|
+
require_relative "utils"
|
|
8
|
+
|
|
9
|
+
module NBA
|
|
10
|
+
# Provides methods to retrieve NBA home page V2 statistics
|
|
11
|
+
module HomePageV2
|
|
12
|
+
# Stat categories available in home page V2
|
|
13
|
+
STAT_CATEGORIES = {
|
|
14
|
+
pts: "HomePageStat1",
|
|
15
|
+
reb: "HomePageStat2",
|
|
16
|
+
ast: "HomePageStat3",
|
|
17
|
+
stl: "HomePageStat4",
|
|
18
|
+
fg_pct: "HomePageStat5",
|
|
19
|
+
ft_pct: "HomePageStat6",
|
|
20
|
+
fg3_pct: "HomePageStat7",
|
|
21
|
+
blk: "HomePageStat8"
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
# Retrieves home page V2 statistics for a stat category
|
|
25
|
+
#
|
|
26
|
+
# @api public
|
|
27
|
+
# @example
|
|
28
|
+
# stats = NBA::HomePageV2.all(stat_category: :pts, season: 2023)
|
|
29
|
+
# stats.each { |s| puts "#{s.rank}. #{s.team_abbreviation}: #{s.value}" }
|
|
30
|
+
# @param stat_category [Symbol] the stat category (:pts, :reb, :ast, etc.)
|
|
31
|
+
# @param season [Integer] the season year (defaults to current season)
|
|
32
|
+
# @param season_type [String] the season type (Regular Season, Playoffs, etc.)
|
|
33
|
+
# @param game_scope [String] the game scope (Season, Yesterday, etc.)
|
|
34
|
+
# @param player_or_team [String] player or team stats (Player, Team)
|
|
35
|
+
# @param player_scope [String] the player scope (All Players, Rookies)
|
|
36
|
+
# @param stat_type [String] the stat type (Traditional, Advanced, etc.)
|
|
37
|
+
# @param league [String, League] the league ID or League object
|
|
38
|
+
# @param client [Client] the API client to use
|
|
39
|
+
# @return [Collection] a collection of home page stats
|
|
40
|
+
def self.all(stat_category:, season: Utils.current_season, season_type: "Regular Season",
|
|
41
|
+
game_scope: "Season", player_or_team: "Team", player_scope: "All Players",
|
|
42
|
+
stat_type: "Traditional", league: League::NBA, client: CLIENT)
|
|
43
|
+
result_set = STAT_CATEGORIES.fetch(stat_category)
|
|
44
|
+
league_id = Utils.extract_league_id(league)
|
|
45
|
+
opts = {season: season, season_type: season_type, game_scope: game_scope,
|
|
46
|
+
player_or_team: player_or_team, player_scope: player_scope,
|
|
47
|
+
stat_type: stat_type, league_id: league_id}
|
|
48
|
+
response = client.get(build_path(opts))
|
|
49
|
+
parse_response(response, result_set, stat_category)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Builds the API request path
|
|
53
|
+
# @api private
|
|
54
|
+
# @return [String] the request path
|
|
55
|
+
def self.build_path(opts)
|
|
56
|
+
"homepagev2?GameScope=#{opts[:game_scope]}&LeagueID=#{opts[:league_id]}" \
|
|
57
|
+
"&PlayerOrTeam=#{opts[:player_or_team]}&PlayerScope=#{opts[:player_scope]}" \
|
|
58
|
+
"&Season=#{Utils.format_season(opts[:season])}&SeasonType=#{opts[:season_type]}" \
|
|
59
|
+
"&StatType=#{opts[:stat_type]}"
|
|
60
|
+
end
|
|
61
|
+
private_class_method :build_path
|
|
62
|
+
|
|
63
|
+
# Parses the API response
|
|
64
|
+
# @api private
|
|
65
|
+
# @param response [String, nil] the raw API response
|
|
66
|
+
# @param result_set [String] the result set name
|
|
67
|
+
# @param stat_category [Symbol] the stat category
|
|
68
|
+
# @return [Collection] parsed stats
|
|
69
|
+
def self.parse_response(response, result_set, stat_category)
|
|
70
|
+
ResponseParser.parse(response, result_set: result_set) do |data|
|
|
71
|
+
build_stat(data, stat_category)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
private_class_method :parse_response
|
|
75
|
+
|
|
76
|
+
# Builds a HomePageStat object from raw data
|
|
77
|
+
# @api private
|
|
78
|
+
# @param data [Hash] the row data
|
|
79
|
+
# @param stat_category [Symbol] the stat category
|
|
80
|
+
# @return [HomePageStat] the stat object
|
|
81
|
+
def self.build_stat(data, stat_category)
|
|
82
|
+
HomePageStat.new(**stat_attributes(data, stat_category))
|
|
83
|
+
end
|
|
84
|
+
private_class_method :build_stat
|
|
85
|
+
|
|
86
|
+
# Extracts stat attributes from data
|
|
87
|
+
# @api private
|
|
88
|
+
# @param data [Hash] the row data
|
|
89
|
+
# @param stat_category [Symbol] the stat category name
|
|
90
|
+
# @return [Hash] stat attributes
|
|
91
|
+
def self.stat_attributes(data, stat_category)
|
|
92
|
+
{rank: data["RANK"], team_id: data["TEAM_ID"],
|
|
93
|
+
team_abbreviation: data["TEAM_ABBREVIATION"],
|
|
94
|
+
team_name: data["TEAM_NAME"],
|
|
95
|
+
value: extract_value(data), stat_name: stat_category}
|
|
96
|
+
end
|
|
97
|
+
private_class_method :stat_attributes
|
|
98
|
+
|
|
99
|
+
# Extracts the stat value from data (different keys per result set)
|
|
100
|
+
# @api private
|
|
101
|
+
# @param data [Hash] the row data
|
|
102
|
+
# @return [Float, nil] the stat value
|
|
103
|
+
def self.extract_value(data)
|
|
104
|
+
value_keys = %w[PTS REB AST STL FG_PCT FT_PCT FG3_PCT BLK]
|
|
105
|
+
value_keys.each { |key| return data.fetch(key) if data.key?(key) }
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
108
|
+
private_class_method :extract_value
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "box_score_hustle_player_stat"
|
|
5
|
+
require_relative "box_score_hustle_team_stat"
|
|
6
|
+
require_relative "utils"
|
|
7
|
+
|
|
8
|
+
module NBA
|
|
9
|
+
# Provides methods to retrieve hustle statistics for a game via hustlestatsboxscore endpoint
|
|
10
|
+
module HustleStatsBoxScore
|
|
11
|
+
# Result set name for availability status
|
|
12
|
+
# @return [String] the result set name
|
|
13
|
+
HUSTLE_STATS_AVAILABLE = "HustleStatsAvailable".freeze
|
|
14
|
+
|
|
15
|
+
# Result set name for player stats
|
|
16
|
+
# @return [String] the result set name
|
|
17
|
+
PLAYER_STATS = "PlayerStats".freeze
|
|
18
|
+
|
|
19
|
+
# Result set name for team stats
|
|
20
|
+
# @return [String] the result set name
|
|
21
|
+
TEAM_STATS = "TeamStats".freeze
|
|
22
|
+
|
|
23
|
+
# API endpoint path
|
|
24
|
+
# @return [String] the endpoint path
|
|
25
|
+
ENDPOINT = "hustlestatsboxscore".freeze
|
|
26
|
+
|
|
27
|
+
# Retrieves hustle statistics for players in a game
|
|
28
|
+
#
|
|
29
|
+
# @api public
|
|
30
|
+
# @example
|
|
31
|
+
# stats = NBA::HustleStatsBoxScore.player_stats(game: "0022400001")
|
|
32
|
+
# @param game [String, Game] the game ID or Game object
|
|
33
|
+
# @param client [Client] the API client to use
|
|
34
|
+
# @return [Collection] a collection of player hustle stats
|
|
35
|
+
def self.player_stats(game:, client: CLIENT)
|
|
36
|
+
game_id = Utils.extract_id(game)
|
|
37
|
+
parse_stats(client.get("#{ENDPOINT}?GameID=#{game_id}"), game_id, PLAYER_STATS, :build_player_stat)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Retrieves hustle statistics for teams in a game
|
|
41
|
+
#
|
|
42
|
+
# @api public
|
|
43
|
+
# @example
|
|
44
|
+
# stats = NBA::HustleStatsBoxScore.team_stats(game: "0022400001")
|
|
45
|
+
# @param game [String, Game] the game ID or Game object
|
|
46
|
+
# @param client [Client] the API client to use
|
|
47
|
+
# @return [Collection] a collection of team hustle stats
|
|
48
|
+
def self.team_stats(game:, client: CLIENT)
|
|
49
|
+
game_id = Utils.extract_id(game)
|
|
50
|
+
parse_stats(client.get("#{ENDPOINT}?GameID=#{game_id}"), game_id, TEAM_STATS, :build_team_stat)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Checks if hustle stats are available for a game
|
|
54
|
+
#
|
|
55
|
+
# @api public
|
|
56
|
+
# @example
|
|
57
|
+
# NBA::HustleStatsBoxScore.available?(game: "0022400001") #=> true
|
|
58
|
+
# @param game [String, Game] the game ID or Game object
|
|
59
|
+
# @param client [Client] the API client to use
|
|
60
|
+
# @return [Boolean] true if hustle stats are available
|
|
61
|
+
def self.available?(game:, client: CLIENT)
|
|
62
|
+
game_id = Utils.extract_id(game)
|
|
63
|
+
stats_available?(client.get("#{ENDPOINT}?GameID=#{game_id}"))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Parses hustle stats from API response
|
|
67
|
+
# @api private
|
|
68
|
+
# @param response [String] the API response
|
|
69
|
+
# @param game_id [String] the game ID
|
|
70
|
+
# @param result_set_name [String] the result set name to find
|
|
71
|
+
# @param builder_method [Symbol] the method to build stat objects
|
|
72
|
+
# @return [Collection] collection of stat objects
|
|
73
|
+
def self.parse_stats(response, game_id, result_set_name, builder_method)
|
|
74
|
+
return Collection.new unless response
|
|
75
|
+
|
|
76
|
+
result_set = find_result_set(JSON.parse(response), result_set_name)
|
|
77
|
+
return Collection.new unless result_set
|
|
78
|
+
|
|
79
|
+
headers = result_set["headers"]
|
|
80
|
+
rows = result_set["rowSet"]
|
|
81
|
+
return Collection.new unless headers && rows
|
|
82
|
+
|
|
83
|
+
Collection.new(rows.map { |row| __send__(builder_method, headers, row, game_id) })
|
|
84
|
+
end
|
|
85
|
+
private_class_method :parse_stats
|
|
86
|
+
|
|
87
|
+
# Checks if hustle stats are available in the response
|
|
88
|
+
# @api private
|
|
89
|
+
# @param response [String] the API response
|
|
90
|
+
# @return [Boolean] true if stats are available
|
|
91
|
+
def self.stats_available?(response)
|
|
92
|
+
return false unless response
|
|
93
|
+
|
|
94
|
+
result_set = find_result_set(JSON.parse(response), HUSTLE_STATS_AVAILABLE)
|
|
95
|
+
return false unless result_set
|
|
96
|
+
|
|
97
|
+
rows = result_set["rowSet"]
|
|
98
|
+
headers = result_set["headers"]
|
|
99
|
+
return false unless rows && !rows.empty? && headers
|
|
100
|
+
|
|
101
|
+
headers.zip(rows.first).to_h["HUSTLE_STATUS"].eql?(1)
|
|
102
|
+
end
|
|
103
|
+
private_class_method :stats_available?
|
|
104
|
+
|
|
105
|
+
# Finds a result set by name in the response data
|
|
106
|
+
# @api private
|
|
107
|
+
# @param data [Hash] the parsed JSON data
|
|
108
|
+
# @param name [String] the result set name to find
|
|
109
|
+
# @return [Hash, nil] the result set hash or nil
|
|
110
|
+
def self.find_result_set(data, name)
|
|
111
|
+
result_sets = data["resultSets"]
|
|
112
|
+
return unless result_sets
|
|
113
|
+
|
|
114
|
+
result_sets.find { |rs| rs.fetch("name").eql?(name) }
|
|
115
|
+
end
|
|
116
|
+
private_class_method :find_result_set
|
|
117
|
+
|
|
118
|
+
# Builds a player stat object from row data
|
|
119
|
+
# @api private
|
|
120
|
+
# @param headers [Array<String>] the column headers
|
|
121
|
+
# @param row [Array] the row data
|
|
122
|
+
# @param game_id [String] the game ID
|
|
123
|
+
# @return [BoxScoreHustlePlayerStat] the player stat object
|
|
124
|
+
def self.build_player_stat(headers, row, game_id)
|
|
125
|
+
data = headers.zip(row).to_h
|
|
126
|
+
BoxScoreHustlePlayerStat.new(**player_identity(data, game_id), **hustle_stats(data))
|
|
127
|
+
end
|
|
128
|
+
private_class_method :build_player_stat
|
|
129
|
+
|
|
130
|
+
# Builds a team stat object from row data
|
|
131
|
+
# @api private
|
|
132
|
+
# @param headers [Array<String>] the column headers
|
|
133
|
+
# @param row [Array] the row data
|
|
134
|
+
# @param game_id [String] the game ID
|
|
135
|
+
# @return [BoxScoreHustleTeamStat] the team stat object
|
|
136
|
+
def self.build_team_stat(headers, row, game_id)
|
|
137
|
+
data = headers.zip(row).to_h
|
|
138
|
+
BoxScoreHustleTeamStat.new(**team_identity(data, game_id), **hustle_stats(data))
|
|
139
|
+
end
|
|
140
|
+
private_class_method :build_team_stat
|
|
141
|
+
|
|
142
|
+
# Extracts player identity attributes from data
|
|
143
|
+
# @api private
|
|
144
|
+
# @param data [Hash] the row data hash
|
|
145
|
+
# @param game_id [String] the game ID
|
|
146
|
+
# @return [Hash] player identity attributes
|
|
147
|
+
def self.player_identity(data, game_id)
|
|
148
|
+
{game_id: game_id, team_id: data.fetch("TEAM_ID"), team_abbreviation: data.fetch("TEAM_ABBREVIATION"),
|
|
149
|
+
team_city: data.fetch("TEAM_CITY"), player_id: data.fetch("PLAYER_ID"), player_name: data.fetch("PLAYER_NAME"),
|
|
150
|
+
start_position: data.fetch("START_POSITION"), comment: data.fetch("COMMENT"),
|
|
151
|
+
min: data.fetch("MINUTES"), pts: data.fetch("PTS")}
|
|
152
|
+
end
|
|
153
|
+
private_class_method :player_identity
|
|
154
|
+
|
|
155
|
+
# Extracts team identity attributes from data
|
|
156
|
+
# @api private
|
|
157
|
+
# @param data [Hash] the row data hash
|
|
158
|
+
# @param game_id [String] the game ID
|
|
159
|
+
# @return [Hash] team identity attributes
|
|
160
|
+
def self.team_identity(data, game_id)
|
|
161
|
+
{game_id: game_id, team_id: data.fetch("TEAM_ID"), team_name: data.fetch("TEAM_NAME"),
|
|
162
|
+
team_abbreviation: data.fetch("TEAM_ABBREVIATION"), team_city: data.fetch("TEAM_CITY"),
|
|
163
|
+
min: data.fetch("MINUTES"), pts: data.fetch("PTS")}
|
|
164
|
+
end
|
|
165
|
+
private_class_method :team_identity
|
|
166
|
+
|
|
167
|
+
# Extracts hustle stats attributes from data
|
|
168
|
+
# @api private
|
|
169
|
+
# @param data [Hash] the row data hash
|
|
170
|
+
# @return [Hash] hustle stats attributes
|
|
171
|
+
def self.hustle_stats(data)
|
|
172
|
+
{contested_shots: data.fetch("CONTESTED_SHOTS"), contested_shots_2pt: data.fetch("CONTESTED_SHOTS_2PT"),
|
|
173
|
+
contested_shots_3pt: data.fetch("CONTESTED_SHOTS_3PT"), deflections: data.fetch("DEFLECTIONS"),
|
|
174
|
+
charges_drawn: data.fetch("CHARGES_DRAWN"), screen_assists: data.fetch("SCREEN_ASSISTS"),
|
|
175
|
+
screen_ast_pts: data.fetch("SCREEN_AST_PTS"), loose_balls_recovered: data.fetch("LOOSE_BALLS_RECOVERED"),
|
|
176
|
+
off_loose_balls_recovered: data.fetch("OFF_LOOSE_BALLS_RECOVERED"),
|
|
177
|
+
def_loose_balls_recovered: data.fetch("DEF_LOOSE_BALLS_RECOVERED"), box_outs: data.fetch("BOX_OUTS"),
|
|
178
|
+
off_box_outs: data.fetch("OFF_BOXOUTS"), def_box_outs: data.fetch("DEF_BOXOUTS")}
|
|
179
|
+
end
|
|
180
|
+
private_class_method :hustle_stats
|
|
181
|
+
end
|
|
182
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "infographic_fan_duel_player_stat"
|
|
5
|
+
require_relative "utils"
|
|
6
|
+
|
|
7
|
+
module NBA
|
|
8
|
+
# Provides methods to retrieve FanDuel infographic player statistics
|
|
9
|
+
module InfographicFanDuelPlayer
|
|
10
|
+
# Result set name for FanDuel player stats
|
|
11
|
+
# @return [String] the result set name
|
|
12
|
+
FAN_DUEL_PLAYER = "FanDuelPlayer".freeze
|
|
13
|
+
|
|
14
|
+
# Retrieves FanDuel infographic statistics for all players in a game
|
|
15
|
+
#
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# stats = NBA::InfographicFanDuelPlayer.find(game: "0022400001")
|
|
19
|
+
# stats.each { |s| puts "#{s.player_name}: #{s.fan_duel_pts} FD pts" }
|
|
20
|
+
# @param game [String, Game] the game ID or Game object
|
|
21
|
+
# @param client [Client] the API client to use
|
|
22
|
+
# @return [Collection] a collection of FanDuel player stats
|
|
23
|
+
def self.find(game:, client: CLIENT)
|
|
24
|
+
game_id = Utils.extract_id(game)
|
|
25
|
+
path = "infographicfanduelplayer?GameID=#{game_id}"
|
|
26
|
+
response = client.get(path)
|
|
27
|
+
parse_response(response, game_id)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Parses the API response
|
|
31
|
+
#
|
|
32
|
+
# @api private
|
|
33
|
+
# @param response [String, nil] the JSON response
|
|
34
|
+
# @param game_id [String] the game ID
|
|
35
|
+
# @return [Collection] collection of player stats
|
|
36
|
+
def self.parse_response(response, game_id)
|
|
37
|
+
return Collection.new unless response
|
|
38
|
+
|
|
39
|
+
data = JSON.parse(response)
|
|
40
|
+
result_set = find_result_set(data)
|
|
41
|
+
return Collection.new unless result_set
|
|
42
|
+
|
|
43
|
+
headers = result_set["headers"]
|
|
44
|
+
rows = result_set["rowSet"]
|
|
45
|
+
return Collection.new unless headers && rows
|
|
46
|
+
|
|
47
|
+
stats = rows.map { |row| build_player_stat(headers, row, game_id) }
|
|
48
|
+
Collection.new(stats)
|
|
49
|
+
end
|
|
50
|
+
private_class_method :parse_response
|
|
51
|
+
|
|
52
|
+
# Finds the result set
|
|
53
|
+
#
|
|
54
|
+
# @api private
|
|
55
|
+
# @param data [Hash] the parsed JSON data
|
|
56
|
+
# @return [Hash, nil] the result set
|
|
57
|
+
def self.find_result_set(data)
|
|
58
|
+
result_sets = data["resultSets"]
|
|
59
|
+
return unless result_sets
|
|
60
|
+
|
|
61
|
+
result_sets.find { |rs| rs["name"].eql?(FAN_DUEL_PLAYER) }
|
|
62
|
+
end
|
|
63
|
+
private_class_method :find_result_set
|
|
64
|
+
|
|
65
|
+
# Builds a player stat from a row
|
|
66
|
+
#
|
|
67
|
+
# @api private
|
|
68
|
+
# @param headers [Array<String>] the column headers
|
|
69
|
+
# @param row [Array] the row data
|
|
70
|
+
# @param game_id [String] the game ID
|
|
71
|
+
# @return [InfographicFanDuelPlayerStat] the player stat object
|
|
72
|
+
def self.build_player_stat(headers, row, game_id)
|
|
73
|
+
data = headers.zip(row).to_h
|
|
74
|
+
InfographicFanDuelPlayerStat.new(**player_stat_attributes(data, game_id))
|
|
75
|
+
end
|
|
76
|
+
private_class_method :build_player_stat
|
|
77
|
+
|
|
78
|
+
# Extracts player stat attributes from row data
|
|
79
|
+
#
|
|
80
|
+
# @api private
|
|
81
|
+
# @param data [Hash] the player stat row data
|
|
82
|
+
# @param game_id [String] the game ID
|
|
83
|
+
# @return [Hash] the player stat attributes
|
|
84
|
+
def self.player_stat_attributes(data, game_id)
|
|
85
|
+
identity_attributes(data, game_id).merge(fantasy_attributes(data), shooting_attributes(data), counting_attributes(data))
|
|
86
|
+
end
|
|
87
|
+
private_class_method :player_stat_attributes
|
|
88
|
+
|
|
89
|
+
# Extracts identity attributes
|
|
90
|
+
#
|
|
91
|
+
# @api private
|
|
92
|
+
# @param data [Hash] the player stat data
|
|
93
|
+
# @param game_id [String] the game ID
|
|
94
|
+
# @return [Hash] the identity attributes
|
|
95
|
+
def self.identity_attributes(data, game_id)
|
|
96
|
+
{game_id: game_id, player_id: data["PLAYER_ID"], player_name: data["PLAYER_NAME"],
|
|
97
|
+
team_id: data["TEAM_ID"], team_name: data["TEAM_NAME"],
|
|
98
|
+
team_abbreviation: data["TEAM_ABBREVIATION"], jersey_num: data["JERSEY_NUM"],
|
|
99
|
+
player_position: data["PLAYER_POSITION"], location: data["LOCATION"]}
|
|
100
|
+
end
|
|
101
|
+
private_class_method :identity_attributes
|
|
102
|
+
|
|
103
|
+
# Extracts fantasy attributes
|
|
104
|
+
#
|
|
105
|
+
# @api private
|
|
106
|
+
# @param data [Hash] the player stat data
|
|
107
|
+
# @return [Hash] the fantasy attributes
|
|
108
|
+
def self.fantasy_attributes(data)
|
|
109
|
+
{fan_duel_pts: data["FAN_DUEL_PTS"], nba_fantasy_pts: data["NBA_FANTASY_PTS"],
|
|
110
|
+
usg_pct: data["USG_PCT"], min: data["MIN"]}
|
|
111
|
+
end
|
|
112
|
+
private_class_method :fantasy_attributes
|
|
113
|
+
|
|
114
|
+
# Extracts shooting attributes
|
|
115
|
+
#
|
|
116
|
+
# @api private
|
|
117
|
+
# @param data [Hash] the player stat data
|
|
118
|
+
# @return [Hash] the shooting attributes
|
|
119
|
+
def self.shooting_attributes(data)
|
|
120
|
+
{fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
|
|
121
|
+
fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"],
|
|
122
|
+
ftm: data["FTM"], fta: data["FTA"], ft_pct: data["FT_PCT"]}
|
|
123
|
+
end
|
|
124
|
+
private_class_method :shooting_attributes
|
|
125
|
+
|
|
126
|
+
# Extracts counting stats attributes
|
|
127
|
+
#
|
|
128
|
+
# @api private
|
|
129
|
+
# @param data [Hash] the player stat data
|
|
130
|
+
# @return [Hash] the counting stats attributes
|
|
131
|
+
def self.counting_attributes(data)
|
|
132
|
+
{oreb: data["OREB"], dreb: data["DREB"], reb: data["REB"],
|
|
133
|
+
ast: data["AST"], tov: data["TOV"], stl: data["STL"],
|
|
134
|
+
blk: data["BLK"], blka: data["BLKA"], pf: data["PF"],
|
|
135
|
+
pfd: data["PFD"], pts: data["PTS"], plus_minus: data["PLUS_MINUS"]}
|
|
136
|
+
end
|
|
137
|
+
private_class_method :counting_attributes
|
|
138
|
+
end
|
|
139
|
+
end
|