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.
Files changed (321) hide show
  1. checksums.yaml +5 -5
  2. data/AGENTS.md +362 -0
  3. data/CHANGELOG.md +169 -0
  4. data/CLAUDE.md +1 -0
  5. data/LICENSE +21 -0
  6. data/README.md +501 -101
  7. data/bin/console +10 -0
  8. data/bin/setup +6 -0
  9. data/exe/nba +8 -0
  10. data/lib/nba/all_time_leader.rb +77 -0
  11. data/lib/nba/all_time_leaders.rb +185 -0
  12. data/lib/nba/assist_leader.rb +92 -0
  13. data/lib/nba/assist_leaders.rb +64 -0
  14. data/lib/nba/assist_tracker.rb +108 -0
  15. data/lib/nba/assist_tracker_entry.rb +206 -0
  16. data/lib/nba/award.rb +128 -0
  17. data/lib/nba/box_score.rb +2 -0
  18. data/lib/nba/box_score_advanced.rb +114 -0
  19. data/lib/nba/box_score_advanced_player_stat.rb +297 -0
  20. data/lib/nba/box_score_advanced_team_stat.rb +237 -0
  21. data/lib/nba/box_score_advanced_v3.rb +124 -0
  22. data/lib/nba/box_score_defensive_player_stat.rb +281 -0
  23. data/lib/nba/box_score_defensive_team_stat.rb +85 -0
  24. data/lib/nba/box_score_defensive_v2.rb +190 -0
  25. data/lib/nba/box_score_four_factors.rb +91 -0
  26. data/lib/nba/box_score_four_factors_player_stat.rb +185 -0
  27. data/lib/nba/box_score_four_factors_team_stat.rb +141 -0
  28. data/lib/nba/box_score_four_factors_v3.rb +133 -0
  29. data/lib/nba/box_score_hustle.rb +226 -0
  30. data/lib/nba/box_score_hustle_player_stat.rb +233 -0
  31. data/lib/nba/box_score_hustle_team_stat.rb +189 -0
  32. data/lib/nba/box_score_matchup_stat.rb +417 -0
  33. data/lib/nba/box_score_matchups_v3.rb +184 -0
  34. data/lib/nba/box_score_misc.rb +100 -0
  35. data/lib/nba/box_score_misc_player_stat.rb +217 -0
  36. data/lib/nba/box_score_misc_team_stat.rb +173 -0
  37. data/lib/nba/box_score_misc_v3.rb +163 -0
  38. data/lib/nba/box_score_player_stat.rb +273 -0
  39. data/lib/nba/box_score_player_track.rb +223 -0
  40. data/lib/nba/box_score_player_track_stat.rb +273 -0
  41. data/lib/nba/box_score_player_track_team_stat.rb +229 -0
  42. data/lib/nba/box_score_scoring.rb +103 -0
  43. data/lib/nba/box_score_scoring_player_stat.rb +241 -0
  44. data/lib/nba/box_score_scoring_team_stat.rb +197 -0
  45. data/lib/nba/box_score_scoring_v3.rb +170 -0
  46. data/lib/nba/box_score_similarity_score.rb +119 -0
  47. data/lib/nba/box_score_similarity_stat.rb +76 -0
  48. data/lib/nba/box_score_starter_bench_stat.rb +257 -0
  49. data/lib/nba/box_score_summary.rb +285 -0
  50. data/lib/nba/box_score_summary_v2.rb +202 -0
  51. data/lib/nba/box_score_summary_v3.rb +120 -0
  52. data/lib/nba/box_score_summary_v3_data.rb +419 -0
  53. data/lib/nba/box_score_team_stat.rb +229 -0
  54. data/lib/nba/box_score_traditional.rb +101 -0
  55. data/lib/nba/box_score_traditional_v3.rb +195 -0
  56. data/lib/nba/box_score_usage.rb +102 -0
  57. data/lib/nba/box_score_usage_player_stat.rb +265 -0
  58. data/lib/nba/box_score_usage_team_stat.rb +221 -0
  59. data/lib/nba/box_score_usage_v3.rb +169 -0
  60. data/lib/nba/box_score_v3_helpers.rb +144 -0
  61. data/lib/nba/career_stats.rb +217 -0
  62. data/lib/nba/cli/display/player_display.rb +98 -0
  63. data/lib/nba/cli/display.rb +178 -0
  64. data/lib/nba/cli/formatters/game_formatters.rb +86 -0
  65. data/lib/nba/cli/formatters/leaders_formatters.rb +26 -0
  66. data/lib/nba/cli/formatters/player_formatters.rb +52 -0
  67. data/lib/nba/cli/formatters/standings_formatters.rb +26 -0
  68. data/lib/nba/cli/formatters/team_formatters.rb +67 -0
  69. data/lib/nba/cli/formatters/time_formatters.rb +82 -0
  70. data/lib/nba/cli/formatters.rb +56 -0
  71. data/lib/nba/cli/helpers.rb +135 -0
  72. data/lib/nba/cli.rb +171 -20
  73. data/lib/nba/client.rb +35 -0
  74. data/lib/nba/collection.rb +89 -0
  75. data/lib/nba/college_player_stat.rb +200 -0
  76. data/lib/nba/common_player_info.rb +142 -0
  77. data/lib/nba/common_playoff_series.rb +90 -0
  78. data/lib/nba/common_team_years.rb +113 -0
  79. data/lib/nba/conference.rb +39 -0
  80. data/lib/nba/connection.rb +84 -0
  81. data/lib/nba/cume_stats_player.rb +358 -0
  82. data/lib/nba/cume_stats_player_game.rb +217 -0
  83. data/lib/nba/cume_stats_player_games.rb +99 -0
  84. data/lib/nba/cume_stats_player_games_entry.rb +25 -0
  85. data/lib/nba/cume_stats_player_total.rb +481 -0
  86. data/lib/nba/cume_stats_team.rb +349 -0
  87. data/lib/nba/cume_stats_team_games.rb +145 -0
  88. data/lib/nba/cume_stats_team_games_entry.rb +25 -0
  89. data/lib/nba/cume_stats_team_player.rb +485 -0
  90. data/lib/nba/cume_stats_team_total.rb +267 -0
  91. data/lib/nba/data.rb +73 -0
  92. data/lib/nba/defense_hub.rb +109 -0
  93. data/lib/nba/defense_hub_stat.rb +57 -0
  94. data/lib/nba/defensive_shot_stat.rb +102 -0
  95. data/lib/nba/division.rb +49 -0
  96. data/lib/nba/draft_board.rb +126 -0
  97. data/lib/nba/draft_board_pick.rb +173 -0
  98. data/lib/nba/draft_combine_anthro_measurement.rb +163 -0
  99. data/lib/nba/draft_combine_drill_result.rb +115 -0
  100. data/lib/nba/draft_combine_drill_results.rb +112 -0
  101. data/lib/nba/draft_combine_non_stationary_shooting.rb +268 -0
  102. data/lib/nba/draft_combine_non_stationary_shooting_result.rb +355 -0
  103. data/lib/nba/draft_combine_player_anthro.rb +133 -0
  104. data/lib/nba/draft_combine_spot_shooting.rb +243 -0
  105. data/lib/nba/draft_combine_spot_shooting_result.rb +419 -0
  106. data/lib/nba/draft_combine_stat.rb +211 -0
  107. data/lib/nba/draft_combine_stats.rb +160 -0
  108. data/lib/nba/draft_history.rb +142 -0
  109. data/lib/nba/draft_pick.rb +154 -0
  110. data/lib/nba/dunk_score_leader.rb +93 -0
  111. data/lib/nba/dunk_score_leaders.rb +77 -0
  112. data/lib/nba/estimated_metrics_stat.rb +152 -0
  113. data/lib/nba/fantasy_profile_stat.rb +142 -0
  114. data/lib/nba/fantasy_widget.rb +72 -0
  115. data/lib/nba/fantasy_widget_player.rb +98 -0
  116. data/lib/nba/found_game.rb +260 -0
  117. data/lib/nba/franchise.rb +136 -0
  118. data/lib/nba/franchise_history.rb +142 -0
  119. data/lib/nba/franchise_leader.rb +147 -0
  120. data/lib/nba/franchise_leaders.rb +162 -0
  121. data/lib/nba/franchise_player.rb +224 -0
  122. data/lib/nba/franchise_players.rb +147 -0
  123. data/lib/nba/game.rb +80 -64
  124. data/lib/nba/game_log.rb +349 -0
  125. data/lib/nba/game_rotation.rb +152 -0
  126. data/lib/nba/game_streak.rb +102 -0
  127. data/lib/nba/games.rb +46 -0
  128. data/lib/nba/home_page_leader.rb +99 -0
  129. data/lib/nba/home_page_leaders.rb +75 -0
  130. data/lib/nba/home_page_stat.rb +57 -0
  131. data/lib/nba/home_page_v2.rb +110 -0
  132. data/lib/nba/hustle_stats_box_score.rb +182 -0
  133. data/lib/nba/infographic_fan_duel_player.rb +139 -0
  134. data/lib/nba/infographic_fan_duel_player_stat.rb +311 -0
  135. data/lib/nba/ist_standing.rb +167 -0
  136. data/lib/nba/ist_standings.rb +81 -0
  137. data/lib/nba/leader.rb +103 -0
  138. data/lib/nba/leaders.rb +110 -0
  139. data/lib/nba/leaders_tile.rb +57 -0
  140. data/lib/nba/leaders_tiles.rb +90 -0
  141. data/lib/nba/league.rb +37 -0
  142. data/lib/nba/league_dash_lineup_stat.rb +270 -0
  143. data/lib/nba/league_dash_lineups.rb +177 -0
  144. data/lib/nba/league_dash_opp_pt_shot.rb +150 -0
  145. data/lib/nba/league_dash_player_bio_stat.rb +217 -0
  146. data/lib/nba/league_dash_player_bio_stats.rb +164 -0
  147. data/lib/nba/league_dash_player_clutch.rb +212 -0
  148. data/lib/nba/league_dash_player_clutch_stat.rb +271 -0
  149. data/lib/nba/league_dash_player_pt_shot.rb +152 -0
  150. data/lib/nba/league_dash_player_pt_shot_stat.rb +193 -0
  151. data/lib/nba/league_dash_player_shot_location_stat.rb +265 -0
  152. data/lib/nba/league_dash_player_shot_locations.rb +210 -0
  153. data/lib/nba/league_dash_player_stat.rb +306 -0
  154. data/lib/nba/league_dash_player_stats.rb +176 -0
  155. data/lib/nba/league_dash_pt_defend.rb +160 -0
  156. data/lib/nba/league_dash_pt_defend_stat.rb +145 -0
  157. data/lib/nba/league_dash_pt_stats.rb +152 -0
  158. data/lib/nba/league_dash_pt_stats_stat.rb +169 -0
  159. data/lib/nba/league_dash_pt_team_defend.rb +158 -0
  160. data/lib/nba/league_dash_pt_team_defend_stat.rb +110 -0
  161. data/lib/nba/league_dash_team_clutch.rb +211 -0
  162. data/lib/nba/league_dash_team_clutch_stat.rb +237 -0
  163. data/lib/nba/league_dash_team_pt_shot.rb +150 -0
  164. data/lib/nba/league_dash_team_pt_shot_stat.rb +166 -0
  165. data/lib/nba/league_dash_team_shot_location_stat.rb +230 -0
  166. data/lib/nba/league_dash_team_shot_locations.rb +208 -0
  167. data/lib/nba/league_dash_team_stat.rb +275 -0
  168. data/lib/nba/league_dash_team_stats.rb +172 -0
  169. data/lib/nba/league_game_finder.rb +170 -0
  170. data/lib/nba/league_game_log.rb +224 -0
  171. data/lib/nba/league_hustle_stats_player.rb +161 -0
  172. data/lib/nba/league_hustle_stats_player_stat.rb +253 -0
  173. data/lib/nba/league_hustle_stats_team.rb +157 -0
  174. data/lib/nba/league_hustle_stats_team_stat.rb +179 -0
  175. data/lib/nba/league_lineup_viz.rb +184 -0
  176. data/lib/nba/league_lineup_viz_stat.rb +214 -0
  177. data/lib/nba/league_player_on_details.rb +175 -0
  178. data/lib/nba/league_player_on_details_stat.rb +313 -0
  179. data/lib/nba/league_season_matchup_stat.rb +241 -0
  180. data/lib/nba/league_season_matchups.rb +181 -0
  181. data/lib/nba/league_standing.rb +284 -0
  182. data/lib/nba/league_standings.rb +159 -0
  183. data/lib/nba/league_wide_shot_stat.rb +62 -0
  184. data/lib/nba/live_action.rb +240 -0
  185. data/lib/nba/live_box_score.rb +143 -0
  186. data/lib/nba/live_connection.rb +84 -0
  187. data/lib/nba/live_game.rb +230 -0
  188. data/lib/nba/live_play_by_play.rb +120 -0
  189. data/lib/nba/live_player_stat.rb +276 -0
  190. data/lib/nba/live_scoreboard.rb +102 -0
  191. data/lib/nba/matchup_rollup.rb +98 -0
  192. data/lib/nba/matchups_rollup.rb +81 -0
  193. data/lib/nba/pass_stat.rb +209 -0
  194. data/lib/nba/play.rb +258 -0
  195. data/lib/nba/play_by_play.rb +85 -0
  196. data/lib/nba/play_by_play_v3.rb +91 -0
  197. data/lib/nba/play_type_stat.rb +206 -0
  198. data/lib/nba/player.rb +242 -24
  199. data/lib/nba/player_awards.rb +110 -0
  200. data/lib/nba/player_career_by_college.rb +86 -0
  201. data/lib/nba/player_career_by_college_rollup.rb +143 -0
  202. data/lib/nba/player_career_stats.rb +77 -0
  203. data/lib/nba/player_compare.rb +156 -0
  204. data/lib/nba/player_comparison_stat.rb +242 -0
  205. data/lib/nba/player_dash_pt_pass.rb +164 -0
  206. data/lib/nba/player_dash_pt_reb.rb +235 -0
  207. data/lib/nba/player_dash_pt_shot_defend.rb +119 -0
  208. data/lib/nba/player_dash_pt_shots.rb +279 -0
  209. data/lib/nba/player_dashboard.rb +259 -0
  210. data/lib/nba/player_dashboard_stat.rb +248 -0
  211. data/lib/nba/player_estimated_metrics.rb +84 -0
  212. data/lib/nba/player_fantasy_profile_bar_graph.rb +147 -0
  213. data/lib/nba/player_game_log.rb +72 -0
  214. data/lib/nba/player_game_logs.rb +117 -0
  215. data/lib/nba/player_game_streak_finder.rb +108 -0
  216. data/lib/nba/player_index.rb +135 -0
  217. data/lib/nba/player_index_entry.rb +266 -0
  218. data/lib/nba/player_info.rb +225 -0
  219. data/lib/nba/player_next_n_games.rb +64 -0
  220. data/lib/nba/player_profile_v2.rb +169 -0
  221. data/lib/nba/player_vs_player.rb +153 -0
  222. data/lib/nba/players.rb +107 -0
  223. data/lib/nba/playoff_matchup.rb +84 -0
  224. data/lib/nba/playoff_picture.rb +98 -0
  225. data/lib/nba/playoff_series.rb +76 -0
  226. data/lib/nba/position.rb +48 -0
  227. data/lib/nba/rebound_stat.rb +189 -0
  228. data/lib/nba/response_parser.rb +116 -0
  229. data/lib/nba/roster.rb +74 -0
  230. data/lib/nba/rotation_entry.rb +154 -0
  231. data/lib/nba/schedule.rb +183 -0
  232. data/lib/nba/schedule_international.rb +182 -0
  233. data/lib/nba/scheduled_game.rb +240 -0
  234. data/lib/nba/scoreboard.rb +183 -0
  235. data/lib/nba/scoreboard_v3.rb +104 -0
  236. data/lib/nba/shot.rb +208 -0
  237. data/lib/nba/shot_chart.rb +75 -0
  238. data/lib/nba/shot_chart_league_wide.rb +102 -0
  239. data/lib/nba/shot_chart_lineup_detail.rb +109 -0
  240. data/lib/nba/shot_stat.rb +174 -0
  241. data/lib/nba/standing.rb +129 -0
  242. data/lib/nba/standings.rb +75 -0
  243. data/lib/nba/static.rb +107 -0
  244. data/lib/nba/synergy_play_types.rb +211 -0
  245. data/lib/nba/team.rb +203 -127
  246. data/lib/nba/team_and_players_vs_players.rb +227 -0
  247. data/lib/nba/team_and_players_vs_players_stat.rb +155 -0
  248. data/lib/nba/team_dash_pt_pass.rb +157 -0
  249. data/lib/nba/team_dash_pt_reb.rb +216 -0
  250. data/lib/nba/team_dash_pt_shots.rb +244 -0
  251. data/lib/nba/team_dashboard.rb +275 -0
  252. data/lib/nba/team_dashboard_stat.rb +248 -0
  253. data/lib/nba/team_detail.rb +117 -0
  254. data/lib/nba/team_details.rb +173 -0
  255. data/lib/nba/team_estimated_metrics.rb +91 -0
  256. data/lib/nba/team_estimated_metrics_stat.rb +146 -0
  257. data/lib/nba/team_game_log.rb +143 -0
  258. data/lib/nba/team_game_log_entry.rb +246 -0
  259. data/lib/nba/team_game_log_stat.rb +275 -0
  260. data/lib/nba/team_game_logs.rb +163 -0
  261. data/lib/nba/team_game_streak.rb +111 -0
  262. data/lib/nba/team_game_streak_finder.rb +109 -0
  263. data/lib/nba/team_historical_leader.rb +207 -0
  264. data/lib/nba/team_historical_leaders.rb +98 -0
  265. data/lib/nba/team_historical_record.rb +139 -0
  266. data/lib/nba/team_info.rb +150 -0
  267. data/lib/nba/team_info_common.rb +177 -0
  268. data/lib/nba/team_on_off_overall_stat.rb +477 -0
  269. data/lib/nba/team_on_off_player_stat.rb +523 -0
  270. data/lib/nba/team_on_off_player_summary.rb +135 -0
  271. data/lib/nba/team_pass_stat.rb +183 -0
  272. data/lib/nba/team_player_dashboard.rb +212 -0
  273. data/lib/nba/team_player_on_off_details.rb +218 -0
  274. data/lib/nba/team_player_on_off_summary.rb +214 -0
  275. data/lib/nba/team_player_stat.rb +275 -0
  276. data/lib/nba/team_rebound_stat.rb +189 -0
  277. data/lib/nba/team_season_rank.rb +110 -0
  278. data/lib/nba/team_shot_stat.rb +173 -0
  279. data/lib/nba/team_vs_player.rb +151 -0
  280. data/lib/nba/team_vs_player_stat.rb +157 -0
  281. data/lib/nba/team_year.rb +55 -0
  282. data/lib/nba/team_year_by_year_stats.rb +152 -0
  283. data/lib/nba/team_year_stat.rb +282 -0
  284. data/lib/nba/teams.rb +33 -0
  285. data/lib/nba/upcoming_game.rb +115 -0
  286. data/lib/nba/utils.rb +94 -0
  287. data/lib/nba/version.rb +5 -2
  288. data/lib/nba/video_detail.rb +103 -0
  289. data/lib/nba/video_details.rb +118 -0
  290. data/lib/nba/video_details_asset.rb +115 -0
  291. data/lib/nba/video_details_asset_entry.rb +91 -0
  292. data/lib/nba/video_event.rb +83 -0
  293. data/lib/nba/video_event_asset.rb +91 -0
  294. data/lib/nba/video_events.rb +106 -0
  295. data/lib/nba/video_events_asset.rb +107 -0
  296. data/lib/nba/video_status.rb +129 -0
  297. data/lib/nba/video_status_entry.rb +161 -0
  298. data/lib/nba/vs_player_stat.rb +156 -0
  299. data/lib/nba/win_probability.rb +117 -0
  300. data/lib/nba/win_probability_point.rb +140 -0
  301. data/lib/nba.rb +249 -5
  302. data/sig/equalizer.rbs +3 -0
  303. data/sig/nba.rbs +7297 -0
  304. data/sig/shale.rbs +24 -0
  305. data/sig/thor.rbs +19 -0
  306. metadata +324 -95
  307. data/.gitignore +0 -18
  308. data/.travis.yml +0 -22
  309. data/Gemfile +0 -23
  310. data/LICENSE.md +0 -22
  311. data/Rakefile +0 -18
  312. data/bin/nba +0 -7
  313. data/cache/teams.json +0 -16529
  314. data/lib/faraday_middleware/scrape_game.rb +0 -41
  315. data/lib/nba/request.rb +0 -37
  316. data/nba.gemspec +0 -28
  317. data/spec/fixtures/games.html +0 -785
  318. data/spec/fixtures/teams.json +0 -16529
  319. data/spec/game_spec.rb +0 -40
  320. data/spec/spec_helper.rb +0 -25
  321. data/spec/team_spec.rb +0 -93
@@ -0,0 +1,235 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "rebound_stat"
5
+ require_relative "utils"
6
+
7
+ module NBA
8
+ # Provides methods to retrieve player tracking rebound statistics
9
+ #
10
+ # @api public
11
+ module PlayerDashPtReb
12
+ # Result set name for overall rebounding
13
+ # @return [String] the result set name
14
+ OVERALL = "OverallRebounding".freeze
15
+
16
+ # Result set name for number contested rebounding
17
+ # @return [String] the result set name
18
+ NUM_CONTESTED = "NumContestedRebounding".freeze
19
+
20
+ # Result set name for rebound distance rebounding
21
+ # @return [String] the result set name
22
+ REB_DISTANCE = "RebDistanceRebounding".freeze
23
+
24
+ # Result set name for shot distance rebounding
25
+ # @return [String] the result set name
26
+ SHOT_DISTANCE = "ShotDistanceRebounding".freeze
27
+
28
+ # Result set name for shot type rebounding
29
+ # @return [String] the result set name
30
+ SHOT_TYPE = "ShotTypeRebounding".freeze
31
+
32
+ # Retrieves overall rebounding statistics for a player
33
+ #
34
+ # @api public
35
+ # @example
36
+ # stats = NBA::PlayerDashPtReb.overall(player: 201939)
37
+ # stats.first.reb #=> 5.7
38
+ # @param player [Integer, Player] the player ID or Player object
39
+ # @param team [Integer, Team] the team ID or Team object
40
+ # @param season [Integer] the season year
41
+ # @param season_type [String] the season type
42
+ # @param per_mode [String] the per mode
43
+ # @param client [Client] the API client to use
44
+ # @return [Collection] a collection of rebound statistics
45
+ def self.overall(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
46
+ per_mode: "PerGame", client: CLIENT)
47
+ options = {season_type: season_type, per_mode: per_mode, result_set: OVERALL}
48
+ fetch_stats(player, team, season, options, client: client)
49
+ end
50
+
51
+ # Retrieves number contested rebounding statistics for a player
52
+ #
53
+ # @api public
54
+ # @example
55
+ # stats = NBA::PlayerDashPtReb.num_contested(player: 201939)
56
+ # stats.each { |s| puts "#{s.reb_num_contesting_range}: #{s.reb}" }
57
+ # @param player [Integer, Player] the player ID or Player object
58
+ # @param team [Integer, Team] the team ID or Team object
59
+ # @param season [Integer] the season year
60
+ # @param season_type [String] the season type
61
+ # @param per_mode [String] the per mode
62
+ # @param client [Client] the API client to use
63
+ # @return [Collection] a collection of rebound statistics
64
+ def self.num_contested(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
65
+ per_mode: "PerGame", client: CLIENT)
66
+ options = {season_type: season_type, per_mode: per_mode, result_set: NUM_CONTESTED}
67
+ fetch_stats(player, team, season, options, client: client)
68
+ end
69
+
70
+ # Retrieves rebound distance rebounding statistics for a player
71
+ #
72
+ # @api public
73
+ # @example
74
+ # stats = NBA::PlayerDashPtReb.reb_distance(player: 201939)
75
+ # stats.each { |s| puts "#{s.reb_dist_range}: #{s.reb}" }
76
+ # @param player [Integer, Player] the player ID or Player object
77
+ # @param team [Integer, Team] the team ID or Team object
78
+ # @param season [Integer] the season year
79
+ # @param season_type [String] the season type
80
+ # @param per_mode [String] the per mode
81
+ # @param client [Client] the API client to use
82
+ # @return [Collection] a collection of rebound statistics
83
+ def self.reb_distance(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
84
+ per_mode: "PerGame", client: CLIENT)
85
+ options = {season_type: season_type, per_mode: per_mode, result_set: REB_DISTANCE}
86
+ fetch_stats(player, team, season, options, client: client)
87
+ end
88
+
89
+ # Retrieves shot distance rebounding statistics for a player
90
+ #
91
+ # @api public
92
+ # @example
93
+ # stats = NBA::PlayerDashPtReb.shot_distance(player: 201939)
94
+ # stats.each { |s| puts "#{s.shot_dist_range}: #{s.reb}" }
95
+ # @param player [Integer, Player] the player ID or Player object
96
+ # @param team [Integer, Team] the team ID or Team object
97
+ # @param season [Integer] the season year
98
+ # @param season_type [String] the season type
99
+ # @param per_mode [String] the per mode
100
+ # @param client [Client] the API client to use
101
+ # @return [Collection] a collection of rebound statistics
102
+ def self.shot_distance(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
103
+ per_mode: "PerGame", client: CLIENT)
104
+ options = {season_type: season_type, per_mode: per_mode, result_set: SHOT_DISTANCE}
105
+ fetch_stats(player, team, season, options, client: client)
106
+ end
107
+
108
+ # Retrieves shot type rebounding statistics for a player
109
+ #
110
+ # @api public
111
+ # @example
112
+ # stats = NBA::PlayerDashPtReb.shot_type(player: 201939)
113
+ # stats.each { |s| puts "#{s.shot_type_range}: #{s.reb}" }
114
+ # @param player [Integer, Player] the player ID or Player object
115
+ # @param team [Integer, Team] the team ID or Team object
116
+ # @param season [Integer] the season year
117
+ # @param season_type [String] the season type
118
+ # @param per_mode [String] the per mode
119
+ # @param client [Client] the API client to use
120
+ # @return [Collection] a collection of rebound statistics
121
+ def self.shot_type(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
122
+ per_mode: "PerGame", client: CLIENT)
123
+ options = {season_type: season_type, per_mode: per_mode, result_set: SHOT_TYPE}
124
+ fetch_stats(player, team, season, options, client: client)
125
+ end
126
+
127
+ # Fetches rebound stats from the API
128
+ #
129
+ # @api private
130
+ # @return [Collection] collection of rebound stats
131
+ def self.fetch_stats(player, team, season, options, client:)
132
+ path = build_path(player, team, season, options.fetch(:season_type), options.fetch(:per_mode))
133
+ response = client.get(path)
134
+ parse_response(response, options.fetch(:result_set))
135
+ end
136
+ private_class_method :fetch_stats
137
+
138
+ # Builds the API path
139
+ #
140
+ # @api private
141
+ # @return [String] the request path
142
+ def self.build_path(player, team, season, season_type, per_mode)
143
+ player_id = Utils.extract_id(player)
144
+ team_id = Utils.extract_id(team)
145
+ season_str = Utils.format_season(season)
146
+ "playerdashptreb?PlayerID=#{player_id}&TeamID=#{team_id}&Season=#{season_str}" \
147
+ "&SeasonType=#{season_type}&PerMode=#{per_mode}&LeagueID=00"
148
+ end
149
+ private_class_method :build_path
150
+
151
+ # Parses the API response into rebound stat objects
152
+ #
153
+ # @api private
154
+ # @return [Collection] collection of rebound stats
155
+ def self.parse_response(response, result_set_name)
156
+ return Collection.new if response.nil? || response.empty?
157
+
158
+ data = JSON.parse(response)
159
+ result_set = find_result_set(data, result_set_name)
160
+ build_collection(result_set)
161
+ end
162
+ private_class_method :parse_response
163
+
164
+ # Finds a result set by name
165
+ #
166
+ # @api private
167
+ # @return [Hash, nil] the result set hash or nil if not found
168
+ def self.find_result_set(data, result_set_name)
169
+ result_sets = data["resultSets"]
170
+ return unless result_sets
171
+
172
+ result_sets.find { |rs| rs["name"].eql?(result_set_name) }
173
+ end
174
+ private_class_method :find_result_set
175
+
176
+ # Builds a collection from a result set
177
+ #
178
+ # @api private
179
+ # @return [Collection] the stats collection
180
+ def self.build_collection(result_set)
181
+ return Collection.new unless result_set
182
+
183
+ headers = result_set["headers"]
184
+ rows = result_set["rowSet"]
185
+ return Collection.new unless headers && rows
186
+
187
+ Collection.new(rows.map { |row| build_rebound_stat(headers.zip(row).to_h) })
188
+ end
189
+ private_class_method :build_collection
190
+
191
+ # Builds a rebound stat from API data
192
+ #
193
+ # @api private
194
+ # @return [ReboundStat] the rebound stat object
195
+ def self.build_rebound_stat(data)
196
+ ReboundStat.new(**identity_info(data), **range_info(data), **rebound_info(data))
197
+ end
198
+ private_class_method :build_rebound_stat
199
+
200
+ # Extracts identity information from data
201
+ #
202
+ # @api private
203
+ # @return [Hash] the identity information hash
204
+ def self.identity_info(data)
205
+ {player_id: data["PLAYER_ID"], player_name_last_first: data["PLAYER_NAME_LAST_FIRST"],
206
+ sort_order: data["SORT_ORDER"], g: data["G"]}
207
+ end
208
+ private_class_method :identity_info
209
+
210
+ # Extracts range information from data
211
+ #
212
+ # @api private
213
+ # @return [Hash] the range information hash
214
+ def self.range_info(data)
215
+ {reb_num_contesting_range: data["REB_NUM_CONTESTING_RANGE"],
216
+ overall: data["OVERALL"], reb_dist_range: data["REB_DIST_RANGE"],
217
+ shot_dist_range: data["SHOT_DIST_RANGE"], shot_type_range: data["SHOT_TYPE_RANGE"]}
218
+ end
219
+ private_class_method :range_info
220
+
221
+ # Extracts rebound information from data
222
+ #
223
+ # @api private
224
+ # @return [Hash] the rebound information hash
225
+ def self.rebound_info(data)
226
+ {reb_frequency: data["REB_FREQUENCY"], oreb: data["OREB"],
227
+ dreb: data["DREB"], reb: data["REB"],
228
+ c_oreb: data["C_OREB"], c_dreb: data["C_DREB"],
229
+ c_reb: data["C_REB"], c_reb_pct: data["C_REB_PCT"],
230
+ uc_oreb: data["UC_OREB"], uc_dreb: data["UC_DREB"],
231
+ uc_reb: data["UC_REB"], uc_reb_pct: data["UC_REB_PCT"]}
232
+ end
233
+ private_class_method :rebound_info
234
+ end
235
+ end
@@ -0,0 +1,119 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "defensive_shot_stat"
5
+ require_relative "utils"
6
+
7
+ module NBA
8
+ # Provides methods to retrieve player tracking defensive shot statistics
9
+ #
10
+ # @api public
11
+ module PlayerDashPtShotDefend
12
+ # Result set name for defending shots
13
+ # @return [String] the result set name
14
+ DEFENDING_SHOTS = "DefendingShots".freeze
15
+
16
+ # Retrieves defensive shot statistics for a player
17
+ #
18
+ # @api public
19
+ # @example
20
+ # stats = NBA::PlayerDashPtShotDefend.find(player: 201939)
21
+ # stats.each { |s| puts "#{s.defense_category}: #{s.d_fg_pct}" }
22
+ # @param player [Integer, Player] the player ID or Player object
23
+ # @param team [Integer, Team] the team ID or Team object
24
+ # @param season [Integer] the season year
25
+ # @param season_type [String] the season type
26
+ # @param per_mode [String] the per mode
27
+ # @param client [Client] the API client to use
28
+ # @return [Collection] a collection of defensive shot statistics
29
+ def self.find(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
30
+ per_mode: "PerGame", client: CLIENT)
31
+ path = build_path(player, team, season, season_type, per_mode)
32
+ response = client.get(path)
33
+ parse_response(response)
34
+ end
35
+
36
+ # Builds the API path
37
+ #
38
+ # @api private
39
+ # @return [String] the request path
40
+ def self.build_path(player, team, season, season_type, per_mode)
41
+ player_id = Utils.extract_id(player)
42
+ team_id = Utils.extract_id(team)
43
+ season_str = Utils.format_season(season)
44
+ "playerdashptshotdefend?PlayerID=#{player_id}&TeamID=#{team_id}&Season=#{season_str}" \
45
+ "&SeasonType=#{season_type}&PerMode=#{per_mode}&LeagueID=00"
46
+ end
47
+ private_class_method :build_path
48
+
49
+ # Parses the API response into defensive shot stat objects
50
+ #
51
+ # @api private
52
+ # @return [Collection] collection of defensive shot stats
53
+ def self.parse_response(response)
54
+ return Collection.new if response.nil? || response.empty?
55
+
56
+ data = JSON.parse(response)
57
+ result_set = find_result_set(data)
58
+ build_collection(result_set)
59
+ end
60
+ private_class_method :parse_response
61
+
62
+ # Finds the defending shots result set
63
+ #
64
+ # @api private
65
+ # @return [Hash, nil] the result set hash or nil if not found
66
+ def self.find_result_set(data)
67
+ result_sets = data["resultSets"]
68
+ return unless result_sets
69
+
70
+ result_sets.find { |rs| rs["name"].eql?(DEFENDING_SHOTS) }
71
+ end
72
+ private_class_method :find_result_set
73
+
74
+ # Builds a collection from a result set
75
+ #
76
+ # @api private
77
+ # @return [Collection] the stats collection
78
+ def self.build_collection(result_set)
79
+ return Collection.new unless result_set
80
+
81
+ headers = result_set["headers"]
82
+ rows = result_set["rowSet"]
83
+ return Collection.new unless headers && rows
84
+
85
+ Collection.new(rows.map { |row| build_defensive_shot_stat(headers.zip(row).to_h) })
86
+ end
87
+ private_class_method :build_collection
88
+
89
+ # Builds a defensive shot stat from API data
90
+ #
91
+ # @api private
92
+ # @return [DefensiveShotStat] the defensive shot stat object
93
+ def self.build_defensive_shot_stat(data)
94
+ DefensiveShotStat.new(**identity_info(data), **defense_info(data))
95
+ end
96
+ private_class_method :build_defensive_shot_stat
97
+
98
+ # Extracts identity information from data
99
+ #
100
+ # @api private
101
+ # @return [Hash] the identity information hash
102
+ def self.identity_info(data)
103
+ {close_def_person_id: data["CLOSE_DEF_PERSON_ID"], gp: data["GP"],
104
+ g: data["G"], defense_category: data["DEFENSE_CATEGORY"]}
105
+ end
106
+ private_class_method :identity_info
107
+
108
+ # Extracts defense information from data
109
+ #
110
+ # @api private
111
+ # @return [Hash] the defense information hash
112
+ def self.defense_info(data)
113
+ {freq: data["FREQ"], d_fgm: data["D_FGM"], d_fga: data["D_FGA"],
114
+ d_fg_pct: data["D_FG_PCT"], normal_fg_pct: data["NORMAL_FG_PCT"],
115
+ pct_plusminus: data["PCT_PLUSMINUS"]}
116
+ end
117
+ private_class_method :defense_info
118
+ end
119
+ end
@@ -0,0 +1,279 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "shot_stat"
5
+ require_relative "utils"
6
+
7
+ module NBA
8
+ # Provides methods to retrieve player tracking shot statistics
9
+ #
10
+ # @api public
11
+ module PlayerDashPtShots
12
+ # Result set name for overall shooting
13
+ # @return [String] the result set name
14
+ OVERALL = "Overall".freeze
15
+
16
+ # Result set name for general shooting
17
+ # @return [String] the result set name
18
+ GENERAL = "GeneralShooting".freeze
19
+
20
+ # Result set name for dribble shooting
21
+ # @return [String] the result set name
22
+ DRIBBLE = "DribbleShooting".freeze
23
+
24
+ # Result set name for touch time shooting
25
+ # @return [String] the result set name
26
+ TOUCH_TIME = "TouchTimeShooting".freeze
27
+
28
+ # Result set name for shot clock shooting
29
+ # @return [String] the result set name
30
+ SHOT_CLOCK = "ShotClockShooting".freeze
31
+
32
+ # Result set name for closest defender shooting
33
+ # @return [String] the result set name
34
+ CLOSEST_DEFENDER = "ClosestDefenderShooting".freeze
35
+
36
+ # Result set name for closest defender 10ft+ shooting
37
+ # @return [String] the result set name
38
+ CLOSEST_DEFENDER_10FT = "ClosestDefender10ftPlusShooting".freeze
39
+
40
+ # Retrieves overall shot statistics for a player
41
+ #
42
+ # @api public
43
+ # @example
44
+ # stats = NBA::PlayerDashPtShots.overall(player: 201939)
45
+ # stats.first.fg_pct #=> 0.472
46
+ # @param player [Integer, Player] the player ID or Player object
47
+ # @param team [Integer, Team] the team ID or Team object
48
+ # @param season [Integer] the season year
49
+ # @param season_type [String] the season type
50
+ # @param per_mode [String] the per mode
51
+ # @param client [Client] the API client to use
52
+ # @return [Collection] a collection of shot statistics
53
+ def self.overall(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
54
+ per_mode: "PerGame", client: CLIENT)
55
+ options = {season_type: season_type, per_mode: per_mode, result_set: OVERALL}
56
+ fetch_stats(player, team, season, options, client: client)
57
+ end
58
+
59
+ # Retrieves general shot statistics for a player
60
+ #
61
+ # @api public
62
+ # @example
63
+ # stats = NBA::PlayerDashPtShots.general(player: 201939)
64
+ # stats.each { |s| puts "#{s.shot_type}: #{s.fg_pct}" }
65
+ # @param player [Integer, Player] the player ID or Player object
66
+ # @param team [Integer, Team] the team ID or Team object
67
+ # @param season [Integer] the season year
68
+ # @param season_type [String] the season type
69
+ # @param per_mode [String] the per mode
70
+ # @param client [Client] the API client to use
71
+ # @return [Collection] a collection of shot statistics
72
+ def self.general(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
73
+ per_mode: "PerGame", client: CLIENT)
74
+ options = {season_type: season_type, per_mode: per_mode, result_set: GENERAL}
75
+ fetch_stats(player, team, season, options, client: client)
76
+ end
77
+
78
+ # Retrieves dribble shot statistics for a player
79
+ #
80
+ # @api public
81
+ # @example
82
+ # stats = NBA::PlayerDashPtShots.dribble(player: 201939)
83
+ # stats.each { |s| puts "#{s.shot_type}: #{s.fg_pct}" }
84
+ # @param player [Integer, Player] the player ID or Player object
85
+ # @param team [Integer, Team] the team ID or Team object
86
+ # @param season [Integer] the season year
87
+ # @param season_type [String] the season type
88
+ # @param per_mode [String] the per mode
89
+ # @param client [Client] the API client to use
90
+ # @return [Collection] a collection of shot statistics
91
+ def self.dribble(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
92
+ per_mode: "PerGame", client: CLIENT)
93
+ options = {season_type: season_type, per_mode: per_mode, result_set: DRIBBLE}
94
+ fetch_stats(player, team, season, options, client: client)
95
+ end
96
+
97
+ # Retrieves touch time shot statistics for a player
98
+ #
99
+ # @api public
100
+ # @example
101
+ # stats = NBA::PlayerDashPtShots.touch_time(player: 201939)
102
+ # stats.each { |s| puts "#{s.shot_type}: #{s.fg_pct}" }
103
+ # @param player [Integer, Player] the player ID or Player object
104
+ # @param team [Integer, Team] the team ID or Team object
105
+ # @param season [Integer] the season year
106
+ # @param season_type [String] the season type
107
+ # @param per_mode [String] the per mode
108
+ # @param client [Client] the API client to use
109
+ # @return [Collection] a collection of shot statistics
110
+ def self.touch_time(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
111
+ per_mode: "PerGame", client: CLIENT)
112
+ options = {season_type: season_type, per_mode: per_mode, result_set: TOUCH_TIME}
113
+ fetch_stats(player, team, season, options, client: client)
114
+ end
115
+
116
+ # Retrieves shot clock shot statistics for a player
117
+ #
118
+ # @api public
119
+ # @example
120
+ # stats = NBA::PlayerDashPtShots.shot_clock(player: 201939)
121
+ # stats.each { |s| puts "#{s.shot_type}: #{s.fg_pct}" }
122
+ # @param player [Integer, Player] the player ID or Player object
123
+ # @param team [Integer, Team] the team ID or Team object
124
+ # @param season [Integer] the season year
125
+ # @param season_type [String] the season type
126
+ # @param per_mode [String] the per mode
127
+ # @param client [Client] the API client to use
128
+ # @return [Collection] a collection of shot statistics
129
+ def self.shot_clock(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
130
+ per_mode: "PerGame", client: CLIENT)
131
+ options = {season_type: season_type, per_mode: per_mode, result_set: SHOT_CLOCK}
132
+ fetch_stats(player, team, season, options, client: client)
133
+ end
134
+
135
+ # Retrieves closest defender shot statistics for a player
136
+ #
137
+ # @api public
138
+ # @example
139
+ # stats = NBA::PlayerDashPtShots.closest_defender(player: 201939)
140
+ # stats.each { |s| puts "#{s.shot_type}: #{s.fg_pct}" }
141
+ # @param player [Integer, Player] the player ID or Player object
142
+ # @param team [Integer, Team] the team ID or Team object
143
+ # @param season [Integer] the season year
144
+ # @param season_type [String] the season type
145
+ # @param per_mode [String] the per mode
146
+ # @param client [Client] the API client to use
147
+ # @return [Collection] a collection of shot statistics
148
+ def self.closest_defender(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
149
+ per_mode: "PerGame", client: CLIENT)
150
+ options = {season_type: season_type, per_mode: per_mode, result_set: CLOSEST_DEFENDER}
151
+ fetch_stats(player, team, season, options, client: client)
152
+ end
153
+
154
+ # Retrieves closest defender 10ft+ shot statistics for a player
155
+ #
156
+ # @api public
157
+ # @example
158
+ # stats = NBA::PlayerDashPtShots.closest_defender_10ft(player: 201939)
159
+ # stats.each { |s| puts "#{s.shot_type}: #{s.fg_pct}" }
160
+ # @param player [Integer, Player] the player ID or Player object
161
+ # @param team [Integer, Team] the team ID or Team object
162
+ # @param season [Integer] the season year
163
+ # @param season_type [String] the season type
164
+ # @param per_mode [String] the per mode
165
+ # @param client [Client] the API client to use
166
+ # @return [Collection] a collection of shot statistics
167
+ def self.closest_defender_10ft(player:, team: 0, season: Utils.current_season, season_type: "Regular Season",
168
+ per_mode: "PerGame", client: CLIENT)
169
+ options = {season_type: season_type, per_mode: per_mode, result_set: CLOSEST_DEFENDER_10FT}
170
+ fetch_stats(player, team, season, options, client: client)
171
+ end
172
+
173
+ # Fetches shot stats from the API
174
+ #
175
+ # @api private
176
+ # @return [Collection] collection of shot stats
177
+ def self.fetch_stats(player, team, season, options, client:)
178
+ path = build_path(player, team, season, options.fetch(:season_type), options.fetch(:per_mode))
179
+ response = client.get(path)
180
+ parse_response(response, options.fetch(:result_set))
181
+ end
182
+ private_class_method :fetch_stats
183
+
184
+ # Builds the API path
185
+ #
186
+ # @api private
187
+ # @return [String] the request path
188
+ def self.build_path(player, team, season, season_type, per_mode)
189
+ player_id = Utils.extract_id(player)
190
+ team_id = Utils.extract_id(team)
191
+ season_str = Utils.format_season(season)
192
+ "playerdashptshots?PlayerID=#{player_id}&TeamID=#{team_id}&Season=#{season_str}" \
193
+ "&SeasonType=#{season_type}&PerMode=#{per_mode}&LeagueID=00"
194
+ end
195
+ private_class_method :build_path
196
+
197
+ # Parses the API response into shot stat objects
198
+ #
199
+ # @api private
200
+ # @return [Collection] collection of shot stats
201
+ def self.parse_response(response, result_set_name)
202
+ return Collection.new if response.nil? || response.empty?
203
+
204
+ data = JSON.parse(response)
205
+ result_set = find_result_set(data, result_set_name)
206
+ build_collection(result_set)
207
+ end
208
+ private_class_method :parse_response
209
+
210
+ # Finds a result set by name
211
+ #
212
+ # @api private
213
+ # @return [Hash, nil] the result set hash or nil if not found
214
+ def self.find_result_set(data, result_set_name)
215
+ result_sets = data["resultSets"]
216
+ return unless result_sets
217
+
218
+ result_sets.find { |rs| rs["name"].eql?(result_set_name) }
219
+ end
220
+ private_class_method :find_result_set
221
+
222
+ # Builds a collection from a result set
223
+ #
224
+ # @api private
225
+ # @return [Collection] the stats collection
226
+ def self.build_collection(result_set)
227
+ return Collection.new unless result_set
228
+
229
+ headers = result_set["headers"]
230
+ rows = result_set["rowSet"]
231
+ return Collection.new unless headers && rows
232
+
233
+ Collection.new(rows.map { |row| build_shot_stat(headers.zip(row).to_h) })
234
+ end
235
+ private_class_method :build_collection
236
+
237
+ # Builds a shot stat from API data
238
+ #
239
+ # @api private
240
+ # @return [ShotStat] the shot stat object
241
+ def self.build_shot_stat(data)
242
+ ShotStat.new(**identity_info(data), **shot_info(data), **shooting_info(data))
243
+ end
244
+ private_class_method :build_shot_stat
245
+
246
+ # Extracts identity information from data
247
+ #
248
+ # @api private
249
+ # @return [Hash] the identity information hash
250
+ def self.identity_info(data)
251
+ {player_id: data["PLAYER_ID"], player_name_last_first: data["PLAYER_NAME_LAST_FIRST"],
252
+ sort_order: data["SORT_ORDER"], gp: data["GP"], g: data["G"]}
253
+ end
254
+ private_class_method :identity_info
255
+
256
+ # Extracts shot information from data
257
+ #
258
+ # @api private
259
+ # @return [Hash] the shot information hash
260
+ def self.shot_info(data)
261
+ {shot_type: data["SHOT_TYPE"], fga_frequency: data["FGA_FREQUENCY"],
262
+ fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
263
+ efg_pct: data["EFG_PCT"]}
264
+ end
265
+ private_class_method :shot_info
266
+
267
+ # Extracts shooting information from data
268
+ #
269
+ # @api private
270
+ # @return [Hash] the shooting information hash
271
+ def self.shooting_info(data)
272
+ {fg2a_frequency: data["FG2A_FREQUENCY"], fg2m: data["FG2M"],
273
+ fg2a: data["FG2A"], fg2_pct: data["FG2_PCT"],
274
+ fg3a_frequency: data["FG3A_FREQUENCY"], fg3m: data["FG3M"],
275
+ fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"]}
276
+ end
277
+ private_class_method :shooting_info
278
+ end
279
+ end