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