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,200 @@
|
|
|
1
|
+
module NBA
|
|
2
|
+
# Represents a player's career stats from a specific college
|
|
3
|
+
class CollegePlayerStat < Shale::Mapper
|
|
4
|
+
include Equalizer.new(:player_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] player_name
|
|
15
|
+
# Returns the player's name
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# stat.player_name #=> "Stephen Curry"
|
|
19
|
+
# @return [String] the player name
|
|
20
|
+
attribute :player_name, Shale::Type::String
|
|
21
|
+
|
|
22
|
+
# @!attribute [rw] college
|
|
23
|
+
# Returns the college name
|
|
24
|
+
# @api public
|
|
25
|
+
# @example
|
|
26
|
+
# stat.college #=> "Davidson"
|
|
27
|
+
# @return [String] the college name
|
|
28
|
+
attribute :college, Shale::Type::String
|
|
29
|
+
|
|
30
|
+
# @!attribute [rw] gp
|
|
31
|
+
# Returns games played
|
|
32
|
+
# @api public
|
|
33
|
+
# @example
|
|
34
|
+
# stat.gp #=> 966
|
|
35
|
+
# @return [Integer] games played
|
|
36
|
+
attribute :gp, Shale::Type::Integer
|
|
37
|
+
|
|
38
|
+
# @!attribute [rw] min
|
|
39
|
+
# Returns total minutes played
|
|
40
|
+
# @api public
|
|
41
|
+
# @example
|
|
42
|
+
# stat.min #=> 31000.0
|
|
43
|
+
# @return [Float] minutes
|
|
44
|
+
attribute :min, Shale::Type::Float
|
|
45
|
+
|
|
46
|
+
# @!attribute [rw] fgm
|
|
47
|
+
# Returns field goals made
|
|
48
|
+
# @api public
|
|
49
|
+
# @example
|
|
50
|
+
# stat.fgm #=> 8000.0
|
|
51
|
+
# @return [Float] field goals made
|
|
52
|
+
attribute :fgm, Shale::Type::Float
|
|
53
|
+
|
|
54
|
+
# @!attribute [rw] fga
|
|
55
|
+
# Returns field goals attempted
|
|
56
|
+
# @api public
|
|
57
|
+
# @example
|
|
58
|
+
# stat.fga #=> 16000.0
|
|
59
|
+
# @return [Float] field goals attempted
|
|
60
|
+
attribute :fga, Shale::Type::Float
|
|
61
|
+
|
|
62
|
+
# @!attribute [rw] fg_pct
|
|
63
|
+
# Returns field goal percentage
|
|
64
|
+
# @api public
|
|
65
|
+
# @example
|
|
66
|
+
# stat.fg_pct #=> 0.475
|
|
67
|
+
# @return [Float] field goal percentage
|
|
68
|
+
attribute :fg_pct, Shale::Type::Float
|
|
69
|
+
|
|
70
|
+
# @!attribute [rw] fg3m
|
|
71
|
+
# Returns three-pointers made
|
|
72
|
+
# @api public
|
|
73
|
+
# @example
|
|
74
|
+
# stat.fg3m #=> 3500.0
|
|
75
|
+
# @return [Float] three-pointers made
|
|
76
|
+
attribute :fg3m, Shale::Type::Float
|
|
77
|
+
|
|
78
|
+
# @!attribute [rw] fg3a
|
|
79
|
+
# Returns three-pointers attempted
|
|
80
|
+
# @api public
|
|
81
|
+
# @example
|
|
82
|
+
# stat.fg3a #=> 8500.0
|
|
83
|
+
# @return [Float] three-pointers attempted
|
|
84
|
+
attribute :fg3a, Shale::Type::Float
|
|
85
|
+
|
|
86
|
+
# @!attribute [rw] fg3_pct
|
|
87
|
+
# Returns three-point percentage
|
|
88
|
+
# @api public
|
|
89
|
+
# @example
|
|
90
|
+
# stat.fg3_pct #=> 0.428
|
|
91
|
+
# @return [Float] three-point percentage
|
|
92
|
+
attribute :fg3_pct, Shale::Type::Float
|
|
93
|
+
|
|
94
|
+
# @!attribute [rw] ftm
|
|
95
|
+
# Returns free throws made
|
|
96
|
+
# @api public
|
|
97
|
+
# @example
|
|
98
|
+
# stat.ftm #=> 4500.0
|
|
99
|
+
# @return [Float] free throws made
|
|
100
|
+
attribute :ftm, Shale::Type::Float
|
|
101
|
+
|
|
102
|
+
# @!attribute [rw] fta
|
|
103
|
+
# Returns free throws attempted
|
|
104
|
+
# @api public
|
|
105
|
+
# @example
|
|
106
|
+
# stat.fta #=> 4900.0
|
|
107
|
+
# @return [Float] free throws attempted
|
|
108
|
+
attribute :fta, Shale::Type::Float
|
|
109
|
+
|
|
110
|
+
# @!attribute [rw] ft_pct
|
|
111
|
+
# Returns free throw percentage
|
|
112
|
+
# @api public
|
|
113
|
+
# @example
|
|
114
|
+
# stat.ft_pct #=> 0.918
|
|
115
|
+
# @return [Float] free throw percentage
|
|
116
|
+
attribute :ft_pct, Shale::Type::Float
|
|
117
|
+
|
|
118
|
+
# @!attribute [rw] oreb
|
|
119
|
+
# Returns offensive rebounds
|
|
120
|
+
# @api public
|
|
121
|
+
# @example
|
|
122
|
+
# stat.oreb #=> 700.0
|
|
123
|
+
# @return [Float] offensive rebounds
|
|
124
|
+
attribute :oreb, Shale::Type::Float
|
|
125
|
+
|
|
126
|
+
# @!attribute [rw] dreb
|
|
127
|
+
# Returns defensive rebounds
|
|
128
|
+
# @api public
|
|
129
|
+
# @example
|
|
130
|
+
# stat.dreb #=> 4200.0
|
|
131
|
+
# @return [Float] defensive rebounds
|
|
132
|
+
attribute :dreb, Shale::Type::Float
|
|
133
|
+
|
|
134
|
+
# @!attribute [rw] reb
|
|
135
|
+
# Returns total rebounds
|
|
136
|
+
# @api public
|
|
137
|
+
# @example
|
|
138
|
+
# stat.reb #=> 4900.0
|
|
139
|
+
# @return [Float] total rebounds
|
|
140
|
+
attribute :reb, Shale::Type::Float
|
|
141
|
+
|
|
142
|
+
# @!attribute [rw] ast
|
|
143
|
+
# Returns assists
|
|
144
|
+
# @api public
|
|
145
|
+
# @example
|
|
146
|
+
# stat.ast #=> 5800.0
|
|
147
|
+
# @return [Float] assists
|
|
148
|
+
attribute :ast, Shale::Type::Float
|
|
149
|
+
|
|
150
|
+
# @!attribute [rw] stl
|
|
151
|
+
# Returns steals
|
|
152
|
+
# @api public
|
|
153
|
+
# @example
|
|
154
|
+
# stat.stl #=> 1400.0
|
|
155
|
+
# @return [Float] steals
|
|
156
|
+
attribute :stl, Shale::Type::Float
|
|
157
|
+
|
|
158
|
+
# @!attribute [rw] blk
|
|
159
|
+
# Returns blocks
|
|
160
|
+
# @api public
|
|
161
|
+
# @example
|
|
162
|
+
# stat.blk #=> 300.0
|
|
163
|
+
# @return [Float] blocks
|
|
164
|
+
attribute :blk, Shale::Type::Float
|
|
165
|
+
|
|
166
|
+
# @!attribute [rw] tov
|
|
167
|
+
# Returns turnovers
|
|
168
|
+
# @api public
|
|
169
|
+
# @example
|
|
170
|
+
# stat.tov #=> 2600.0
|
|
171
|
+
# @return [Float] turnovers
|
|
172
|
+
attribute :tov, Shale::Type::Float
|
|
173
|
+
|
|
174
|
+
# @!attribute [rw] pf
|
|
175
|
+
# Returns personal fouls
|
|
176
|
+
# @api public
|
|
177
|
+
# @example
|
|
178
|
+
# stat.pf #=> 2000.0
|
|
179
|
+
# @return [Float] personal fouls
|
|
180
|
+
attribute :pf, Shale::Type::Float
|
|
181
|
+
|
|
182
|
+
# @!attribute [rw] pts
|
|
183
|
+
# Returns points
|
|
184
|
+
# @api public
|
|
185
|
+
# @example
|
|
186
|
+
# stat.pts #=> 24000.0
|
|
187
|
+
# @return [Float] points
|
|
188
|
+
attribute :pts, Shale::Type::Float
|
|
189
|
+
|
|
190
|
+
# Returns the player object
|
|
191
|
+
#
|
|
192
|
+
# @api public
|
|
193
|
+
# @example
|
|
194
|
+
# stat.player #=> #<NBA::Player>
|
|
195
|
+
# @return [Player, nil] the player object
|
|
196
|
+
def player
|
|
197
|
+
Players.find(player_id)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "player_info"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
|
|
6
|
+
module NBA
|
|
7
|
+
# Provides methods to retrieve detailed player information
|
|
8
|
+
module CommonPlayerInfo
|
|
9
|
+
# Result set name for common player info
|
|
10
|
+
# @return [String] the result set name
|
|
11
|
+
COMMON_PLAYER_INFO = "CommonPlayerInfo".freeze
|
|
12
|
+
|
|
13
|
+
# Retrieves detailed information for a player
|
|
14
|
+
#
|
|
15
|
+
# @api public
|
|
16
|
+
# @example
|
|
17
|
+
# info = NBA::CommonPlayerInfo.find(player: 201939)
|
|
18
|
+
# puts "#{info.display_name} - #{info.position} - #{info.team_name}"
|
|
19
|
+
# @param player [Integer, Player] the player ID or Player object
|
|
20
|
+
# @param client [Client] the API client to use
|
|
21
|
+
# @return [PlayerInfo, nil] the player info
|
|
22
|
+
def self.find(player:, client: CLIENT)
|
|
23
|
+
player_id = extract_player_id(player)
|
|
24
|
+
path = "commonplayerinfo?PlayerID=#{player_id}"
|
|
25
|
+
response = client.get(path)
|
|
26
|
+
parse_response(response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Parses the API response into a PlayerInfo object
|
|
30
|
+
# @api private
|
|
31
|
+
# @param response [String, nil] the JSON response
|
|
32
|
+
# @return [PlayerInfo, nil] the player info
|
|
33
|
+
def self.parse_response(response)
|
|
34
|
+
return unless response
|
|
35
|
+
|
|
36
|
+
data = JSON.parse(response)
|
|
37
|
+
result_set = find_result_set(data)
|
|
38
|
+
return unless result_set
|
|
39
|
+
|
|
40
|
+
headers = result_set["headers"]
|
|
41
|
+
row = result_set.dig("rowSet", 0)
|
|
42
|
+
return unless headers && row
|
|
43
|
+
|
|
44
|
+
build_player_info(headers, row)
|
|
45
|
+
end
|
|
46
|
+
private_class_method :parse_response
|
|
47
|
+
|
|
48
|
+
# Finds the common player info result set
|
|
49
|
+
# @api private
|
|
50
|
+
# @param data [Hash] the parsed JSON data
|
|
51
|
+
# @return [Hash, nil] the result set
|
|
52
|
+
def self.find_result_set(data)
|
|
53
|
+
result_sets = data["resultSets"]
|
|
54
|
+
return unless result_sets
|
|
55
|
+
|
|
56
|
+
result_sets.find { |rs| rs["name"].eql?(COMMON_PLAYER_INFO) }
|
|
57
|
+
end
|
|
58
|
+
private_class_method :find_result_set
|
|
59
|
+
|
|
60
|
+
# Builds a PlayerInfo object from raw data
|
|
61
|
+
# @api private
|
|
62
|
+
# @param headers [Array<String>] the column headers
|
|
63
|
+
# @param row [Array] the row data
|
|
64
|
+
# @return [PlayerInfo] the player info object
|
|
65
|
+
def self.build_player_info(headers, row)
|
|
66
|
+
data = headers.zip(row).to_h
|
|
67
|
+
PlayerInfo.new(**player_info_attributes(data))
|
|
68
|
+
end
|
|
69
|
+
private_class_method :build_player_info
|
|
70
|
+
|
|
71
|
+
# Combines all player info attributes
|
|
72
|
+
# @api private
|
|
73
|
+
# @param data [Hash] the raw data
|
|
74
|
+
# @return [Hash] the combined attributes
|
|
75
|
+
def self.player_info_attributes(data)
|
|
76
|
+
identity_attributes(data).merge(physical_attributes(data), team_attributes(data), draft_attributes(data))
|
|
77
|
+
end
|
|
78
|
+
private_class_method :player_info_attributes
|
|
79
|
+
|
|
80
|
+
# Extracts identity attributes from data
|
|
81
|
+
# @api private
|
|
82
|
+
# @param data [Hash] the raw data
|
|
83
|
+
# @return [Hash] identity attributes
|
|
84
|
+
def self.identity_attributes(data)
|
|
85
|
+
{player_id: data["PERSON_ID"], first_name: data["FIRST_NAME"], last_name: data["LAST_NAME"],
|
|
86
|
+
display_name: data["DISPLAY_FIRST_LAST"], birthdate: data["BIRTHDATE"], school: data["SCHOOL"],
|
|
87
|
+
country: data["COUNTRY"], from_year: data["FROM_YEAR"], to_year: data["TO_YEAR"],
|
|
88
|
+
greatest_75_flag: data["GREATEST_75_FLAG"]}
|
|
89
|
+
end
|
|
90
|
+
private_class_method :identity_attributes
|
|
91
|
+
|
|
92
|
+
# Extracts physical attributes from data
|
|
93
|
+
# @api private
|
|
94
|
+
# @param data [Hash] the raw data
|
|
95
|
+
# @return [Hash] physical attributes
|
|
96
|
+
def self.physical_attributes(data)
|
|
97
|
+
{height: data["HEIGHT"], weight: data["WEIGHT"], season_exp: data["SEASON_EXP"],
|
|
98
|
+
jersey: data["JERSEY"], position: data["POSITION"]}
|
|
99
|
+
end
|
|
100
|
+
private_class_method :physical_attributes
|
|
101
|
+
|
|
102
|
+
# Extracts team attributes from data
|
|
103
|
+
# @api private
|
|
104
|
+
# @param data [Hash] the raw data
|
|
105
|
+
# @return [Hash] team attributes
|
|
106
|
+
def self.team_attributes(data)
|
|
107
|
+
{team_id: data["TEAM_ID"], team_name: data["TEAM_NAME"],
|
|
108
|
+
team_abbreviation: data["TEAM_ABBREVIATION"], team_city: data["TEAM_CITY"]}
|
|
109
|
+
end
|
|
110
|
+
private_class_method :team_attributes
|
|
111
|
+
|
|
112
|
+
# Extracts draft attributes from data
|
|
113
|
+
# @api private
|
|
114
|
+
# @param data [Hash] the raw data
|
|
115
|
+
# @return [Hash] draft attributes
|
|
116
|
+
def self.draft_attributes(data)
|
|
117
|
+
{draft_year: parse_draft_value(data["DRAFT_YEAR"]), draft_round: parse_draft_value(data["DRAFT_ROUND"]),
|
|
118
|
+
draft_number: parse_draft_value(data["DRAFT_NUMBER"])}
|
|
119
|
+
end
|
|
120
|
+
private_class_method :draft_attributes
|
|
121
|
+
|
|
122
|
+
# Parses draft value, handling "Undrafted" case
|
|
123
|
+
# @api private
|
|
124
|
+
# @param value [String, Integer, nil] the draft value
|
|
125
|
+
# @return [Integer, nil] the parsed draft value
|
|
126
|
+
def self.parse_draft_value(value)
|
|
127
|
+
return if value.eql?("Undrafted")
|
|
128
|
+
|
|
129
|
+
value
|
|
130
|
+
end
|
|
131
|
+
private_class_method :parse_draft_value
|
|
132
|
+
|
|
133
|
+
# Extracts player ID from player object or integer
|
|
134
|
+
# @api private
|
|
135
|
+
# @param player [Player, Integer] the player
|
|
136
|
+
# @return [Integer, nil] the player ID
|
|
137
|
+
def self.extract_player_id(player)
|
|
138
|
+
player.instance_of?(Player) ? player.id : player
|
|
139
|
+
end
|
|
140
|
+
private_class_method :extract_player_id
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
|
|
6
|
+
require_relative "playoff_series"
|
|
7
|
+
|
|
8
|
+
module NBA
|
|
9
|
+
# Provides methods to retrieve playoff series data
|
|
10
|
+
module CommonPlayoffSeries
|
|
11
|
+
# Result set name for playoff series
|
|
12
|
+
# @return [String] the result set name
|
|
13
|
+
PLAYOFF_SERIES = "PlayoffSeries".freeze
|
|
14
|
+
|
|
15
|
+
# Retrieves all playoff series for a season
|
|
16
|
+
#
|
|
17
|
+
# @api public
|
|
18
|
+
# @example
|
|
19
|
+
# series = NBA::CommonPlayoffSeries.all(season: 2024)
|
|
20
|
+
# series.each { |s| puts "Game #{s.game_num}: #{s.home_team_id} vs #{s.visitor_team_id}" }
|
|
21
|
+
# @param season [Integer] the season year
|
|
22
|
+
# @param league [String, League] the league ID or League object (default NBA)
|
|
23
|
+
# @param client [Client] the API client to use
|
|
24
|
+
# @return [Collection] a collection of playoff series
|
|
25
|
+
def self.all(season: Utils.current_season, league: League::NBA, client: CLIENT)
|
|
26
|
+
league_id = Utils.extract_league_id(league)
|
|
27
|
+
path = build_path(season, league_id)
|
|
28
|
+
response = client.get(path)
|
|
29
|
+
parse_response(response)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Builds the API request path
|
|
33
|
+
# @api private
|
|
34
|
+
# @return [String] the request path
|
|
35
|
+
def self.build_path(season, league_id)
|
|
36
|
+
season_str = Utils.format_season(season)
|
|
37
|
+
"commonplayoffseries?LeagueID=#{league_id}&Season=#{season_str}"
|
|
38
|
+
end
|
|
39
|
+
private_class_method :build_path
|
|
40
|
+
|
|
41
|
+
# Parses the API response into playoff series objects
|
|
42
|
+
# @api private
|
|
43
|
+
# @return [Collection] collection of playoff series
|
|
44
|
+
def self.parse_response(response)
|
|
45
|
+
return Collection.new unless response
|
|
46
|
+
|
|
47
|
+
data = JSON.parse(response)
|
|
48
|
+
result_set = find_result_set(data)
|
|
49
|
+
return Collection.new unless result_set
|
|
50
|
+
|
|
51
|
+
headers = result_set["headers"]
|
|
52
|
+
rows = result_set["rowSet"]
|
|
53
|
+
return Collection.new unless headers && rows
|
|
54
|
+
|
|
55
|
+
series = rows.map { |row| build_series(headers, row) }
|
|
56
|
+
Collection.new(series)
|
|
57
|
+
end
|
|
58
|
+
private_class_method :parse_response
|
|
59
|
+
|
|
60
|
+
# Finds the playoff series result set in the response
|
|
61
|
+
# @api private
|
|
62
|
+
# @return [Hash, nil] the result set hash
|
|
63
|
+
def self.find_result_set(data)
|
|
64
|
+
result_sets = data["resultSets"]
|
|
65
|
+
return unless result_sets
|
|
66
|
+
|
|
67
|
+
result_sets.find { |rs| rs["name"].eql?(PLAYOFF_SERIES) }
|
|
68
|
+
end
|
|
69
|
+
private_class_method :find_result_set
|
|
70
|
+
|
|
71
|
+
# Builds a PlayoffSeries object from raw data
|
|
72
|
+
# @api private
|
|
73
|
+
# @return [PlayoffSeries] the playoff series object
|
|
74
|
+
def self.build_series(headers, row)
|
|
75
|
+
data = headers.zip(row).to_h
|
|
76
|
+
PlayoffSeries.new(**series_attributes(data))
|
|
77
|
+
end
|
|
78
|
+
private_class_method :build_series
|
|
79
|
+
|
|
80
|
+
# Extracts series attributes from data
|
|
81
|
+
# @api private
|
|
82
|
+
# @return [Hash] series attributes
|
|
83
|
+
def self.series_attributes(data)
|
|
84
|
+
{game_id: data["GAME_ID"], home_team_id: data["HOME_TEAM_ID"],
|
|
85
|
+
visitor_team_id: data["VISITOR_TEAM_ID"], series_id: data["SERIES_ID"],
|
|
86
|
+
game_num: data["GAME_NUM"]}
|
|
87
|
+
end
|
|
88
|
+
private_class_method :series_attributes
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require_relative "client"
|
|
3
|
+
require_relative "collection"
|
|
4
|
+
require_relative "team_year"
|
|
5
|
+
|
|
6
|
+
module NBA
|
|
7
|
+
# Provides methods to retrieve team year history
|
|
8
|
+
module CommonTeamYears
|
|
9
|
+
# Result set name
|
|
10
|
+
# @return [String] the result set name
|
|
11
|
+
TEAM_YEARS = "TeamYears".freeze
|
|
12
|
+
|
|
13
|
+
# Retrieves all years a team has participated in the league
|
|
14
|
+
#
|
|
15
|
+
# @api public
|
|
16
|
+
# @example
|
|
17
|
+
# years = NBA::CommonTeamYears.all
|
|
18
|
+
# gsw_years = years.select { |y| y.team_id == NBA::Team::GSW }
|
|
19
|
+
# puts "Warriors have played #{gsw_years.size} seasons"
|
|
20
|
+
# @param client [Client] the API client to use
|
|
21
|
+
# @return [Collection] a collection of team years
|
|
22
|
+
def self.all(client: CLIENT)
|
|
23
|
+
path = "commonteamyears?LeagueID=00"
|
|
24
|
+
response = client.get(path)
|
|
25
|
+
parse_response(response)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Retrieves years for a specific team
|
|
29
|
+
#
|
|
30
|
+
# @api public
|
|
31
|
+
# @example
|
|
32
|
+
# years = NBA::CommonTeamYears.find(team: NBA::Team::GSW)
|
|
33
|
+
# puts "First year: #{years.first.year}, Latest: #{years.last.year}"
|
|
34
|
+
# @param team [Integer, Team] the team ID or Team object
|
|
35
|
+
# @param client [Client] the API client to use
|
|
36
|
+
# @return [Collection] a collection of team years for the team
|
|
37
|
+
def self.find(team:, client: CLIENT)
|
|
38
|
+
team_id = extract_team_id(team)
|
|
39
|
+
years = all(client: client)
|
|
40
|
+
Collection.new(years.select { |y| y.team_id.eql?(team_id) })
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Parses the API response
|
|
44
|
+
# @api private
|
|
45
|
+
# @param response [String, nil] the JSON response
|
|
46
|
+
# @return [Collection] collection of team years
|
|
47
|
+
def self.parse_response(response)
|
|
48
|
+
return Collection.new unless response
|
|
49
|
+
|
|
50
|
+
data = JSON.parse(response)
|
|
51
|
+
result_set = find_result_set(data)
|
|
52
|
+
return Collection.new unless result_set
|
|
53
|
+
|
|
54
|
+
build_team_years(result_set)
|
|
55
|
+
end
|
|
56
|
+
private_class_method :parse_response
|
|
57
|
+
|
|
58
|
+
# Finds the result set
|
|
59
|
+
# @api private
|
|
60
|
+
# @param data [Hash] the parsed JSON
|
|
61
|
+
# @return [Hash, nil] the result set
|
|
62
|
+
def self.find_result_set(data)
|
|
63
|
+
result_sets = data["resultSets"]
|
|
64
|
+
return unless result_sets
|
|
65
|
+
|
|
66
|
+
result_sets.find { |rs| rs.fetch("name").eql?(TEAM_YEARS) }
|
|
67
|
+
end
|
|
68
|
+
private_class_method :find_result_set
|
|
69
|
+
|
|
70
|
+
# Builds team years collection
|
|
71
|
+
# @api private
|
|
72
|
+
# @param result_set [Hash] the result set
|
|
73
|
+
# @return [Collection] collection of team years
|
|
74
|
+
def self.build_team_years(result_set)
|
|
75
|
+
headers = result_set["headers"]
|
|
76
|
+
rows = result_set["rowSet"]
|
|
77
|
+
return Collection.new unless headers && rows
|
|
78
|
+
|
|
79
|
+
years = rows.map { |row| build_team_year(headers, row) }
|
|
80
|
+
Collection.new(years)
|
|
81
|
+
end
|
|
82
|
+
private_class_method :build_team_years
|
|
83
|
+
|
|
84
|
+
# Builds a team year
|
|
85
|
+
# @api private
|
|
86
|
+
# @param headers [Array<String>] the headers
|
|
87
|
+
# @param row [Array] the row data
|
|
88
|
+
# @return [TeamYear] the team year
|
|
89
|
+
def self.build_team_year(headers, row)
|
|
90
|
+
data = headers.zip(row).to_h
|
|
91
|
+
TeamYear.new(**team_year_attributes(data))
|
|
92
|
+
end
|
|
93
|
+
private_class_method :build_team_year
|
|
94
|
+
|
|
95
|
+
# Extracts team year attributes
|
|
96
|
+
# @api private
|
|
97
|
+
# @param data [Hash] the raw data
|
|
98
|
+
# @return [Hash] the attributes
|
|
99
|
+
def self.team_year_attributes(data)
|
|
100
|
+
{team_id: data.fetch("TEAM_ID"), year: data.fetch("MAX_YEAR"), abbreviation: data.fetch("ABBREVIATION")}
|
|
101
|
+
end
|
|
102
|
+
private_class_method :team_year_attributes
|
|
103
|
+
|
|
104
|
+
# Extracts team ID
|
|
105
|
+
# @api private
|
|
106
|
+
# @param team [Team, Integer] the team
|
|
107
|
+
# @return [Integer, nil] the team ID
|
|
108
|
+
def self.extract_team_id(team)
|
|
109
|
+
team.instance_of?(Team) ? team.id : team
|
|
110
|
+
end
|
|
111
|
+
private_class_method :extract_team_id
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "equalizer"
|
|
2
|
+
require "shale"
|
|
3
|
+
|
|
4
|
+
module NBA
|
|
5
|
+
# Represents an NBA conference (Eastern or Western)
|
|
6
|
+
class Conference < Shale::Mapper
|
|
7
|
+
include Equalizer.new(:id)
|
|
8
|
+
|
|
9
|
+
# @!attribute [rw] id
|
|
10
|
+
# Returns the unique identifier for the conference
|
|
11
|
+
# @api public
|
|
12
|
+
# @example
|
|
13
|
+
# conference.id #=> 1
|
|
14
|
+
# @return [Integer] the unique identifier for the conference
|
|
15
|
+
attribute :id, Shale::Type::Integer
|
|
16
|
+
|
|
17
|
+
# @!attribute [rw] name
|
|
18
|
+
# Returns the conference name
|
|
19
|
+
# @api public
|
|
20
|
+
# @example
|
|
21
|
+
# conference.name #=> "Eastern"
|
|
22
|
+
# @return [String] the conference name
|
|
23
|
+
attribute :name, Shale::Type::String
|
|
24
|
+
|
|
25
|
+
# @!attribute [rw] link
|
|
26
|
+
# Returns the API link for the conference
|
|
27
|
+
# @api public
|
|
28
|
+
# @example
|
|
29
|
+
# conference.link #=> "/api/v1/conferences/1"
|
|
30
|
+
# @return [String] the API link for the conference
|
|
31
|
+
attribute :link, Shale::Type::String
|
|
32
|
+
|
|
33
|
+
json do
|
|
34
|
+
map "id", to: :id
|
|
35
|
+
map "name", to: :name
|
|
36
|
+
map "link", to: :link
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require "net/http"
|
|
2
|
+
require "openssl"
|
|
3
|
+
require "stringio"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "zlib"
|
|
6
|
+
|
|
7
|
+
module NBA
|
|
8
|
+
# Handles HTTP connections to the NBA API
|
|
9
|
+
class Connection
|
|
10
|
+
# Default base URL for the NBA Stats API
|
|
11
|
+
# @return [String] the default base URL
|
|
12
|
+
BASE_URL = "https://stats.nba.com/stats/".freeze
|
|
13
|
+
|
|
14
|
+
# Returns the base URL for API requests
|
|
15
|
+
#
|
|
16
|
+
# @api private
|
|
17
|
+
# @return [String] the base URL
|
|
18
|
+
attr_reader :base_url
|
|
19
|
+
|
|
20
|
+
# Initializes a new Connection object
|
|
21
|
+
#
|
|
22
|
+
# @api public
|
|
23
|
+
# @example
|
|
24
|
+
# connection = NBA::Connection.new
|
|
25
|
+
# @param base_url [String] the base URL for API requests
|
|
26
|
+
# @return [NBA::Connection] a new connection instance
|
|
27
|
+
def initialize(base_url: BASE_URL)
|
|
28
|
+
@base_url = base_url
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Makes a GET request to the specified path
|
|
32
|
+
#
|
|
33
|
+
# @api public
|
|
34
|
+
# @example
|
|
35
|
+
# connection.get("teams")
|
|
36
|
+
# @param path [String] the API path to request
|
|
37
|
+
# @return [String] the response body
|
|
38
|
+
def get(path)
|
|
39
|
+
uri = URI.join(base_url, path)
|
|
40
|
+
hostname = uri.hostname or raise ArgumentError, "Invalid URI: #{uri}"
|
|
41
|
+
request = Net::HTTP::Get.new(uri)
|
|
42
|
+
apply_headers(request)
|
|
43
|
+
|
|
44
|
+
Net::HTTP.start(hostname, uri.port, use_ssl: uri.scheme.eql?("https")) do |http|
|
|
45
|
+
response = http.request(request)
|
|
46
|
+
decode_body(response) if response.is_a?(Net::HTTPSuccess)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Applies the required headers for NBA Stats API requests
|
|
53
|
+
#
|
|
54
|
+
# @api private
|
|
55
|
+
# @param request [Net::HTTP::Get] the request object
|
|
56
|
+
# @return [void]
|
|
57
|
+
def apply_headers(request)
|
|
58
|
+
request["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " \
|
|
59
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
60
|
+
request["Accept"] = "application/json, text/plain, */*"
|
|
61
|
+
request["Accept-Language"] = "en-US,en;q=0.9"
|
|
62
|
+
request["Accept-Encoding"] = "gzip, deflate, identity"
|
|
63
|
+
request["Connection"] = "keep-alive"
|
|
64
|
+
request["Referer"] = "https://www.nba.com/"
|
|
65
|
+
request["Origin"] = "https://www.nba.com"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Decodes the response body based on Content-Encoding
|
|
69
|
+
#
|
|
70
|
+
# @api private
|
|
71
|
+
# @param response [Net::HTTPResponse] the HTTP response
|
|
72
|
+
# @return [String, nil] the decoded response body
|
|
73
|
+
def decode_body(response)
|
|
74
|
+
case response["Content-Encoding"]
|
|
75
|
+
when "gzip"
|
|
76
|
+
Zlib::GzipReader.new(StringIO.new(response.body)).read
|
|
77
|
+
when "deflate"
|
|
78
|
+
Zlib::Inflate.inflate(response.body)
|
|
79
|
+
else
|
|
80
|
+
response.body
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|