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,173 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "team_detail"
5
+ require_relative "team_historical_record"
6
+
7
+ module NBA
8
+ # Provides methods to retrieve team details
9
+ module TeamDetails
10
+ # Result set name for team background
11
+ # @return [String] the result set name
12
+ TEAM_BACKGROUND = "TeamBackground".freeze
13
+
14
+ # Result set name for team history
15
+ # @return [String] the result set name
16
+ TEAM_HISTORY = "TeamHistory".freeze
17
+
18
+ # Retrieves detailed information for a team
19
+ #
20
+ # @api public
21
+ # @example
22
+ # detail = NBA::TeamDetails.find(team: NBA::Team::GSW)
23
+ # puts "#{detail.full_name} plays at #{detail.arena}"
24
+ # @param team [Integer, Team] the team ID or Team object
25
+ # @param client [Client] the API client to use
26
+ # @return [TeamDetail, nil] the team detail
27
+ def self.find(team:, client: CLIENT)
28
+ team_id = extract_team_id(team)
29
+ path = "teamdetails?TeamID=#{team_id}"
30
+ response = client.get(path)
31
+ parse_detail_response(response)
32
+ end
33
+
34
+ # Retrieves historical records for a team
35
+ #
36
+ # @api public
37
+ # @example
38
+ # history = NBA::TeamDetails.history(team: NBA::Team::GSW)
39
+ # history.each { |h| puts "#{h.year}: #{h.wins}-#{h.losses}" }
40
+ # @param team [Integer, Team] the team ID or Team object
41
+ # @param client [Client] the API client to use
42
+ # @return [Collection] a collection of historical records
43
+ def self.history(team:, client: CLIENT)
44
+ team_id = extract_team_id(team)
45
+ path = "teamdetails?TeamID=#{team_id}"
46
+ response = client.get(path)
47
+ parse_history_response(response)
48
+ end
49
+
50
+ # Parses the API response into a team detail object
51
+ # @api private
52
+ # @return [TeamDetail, nil] the team detail
53
+ def self.parse_detail_response(response)
54
+ return unless response
55
+
56
+ data = JSON.parse(response)
57
+ result_set = find_result_set(data, TEAM_BACKGROUND)
58
+ return unless result_set
59
+
60
+ headers = result_set["headers"]
61
+ row = result_set.dig("rowSet", 0)
62
+ return unless headers && row
63
+
64
+ build_team_detail(headers, row)
65
+ end
66
+ private_class_method :parse_detail_response
67
+
68
+ # Parses the API response into historical record objects
69
+ # @api private
70
+ # @return [Collection] collection of historical records
71
+ def self.parse_history_response(response)
72
+ return Collection.new unless response
73
+
74
+ data = JSON.parse(response)
75
+ result_set = find_result_set(data, TEAM_HISTORY)
76
+ return Collection.new unless result_set
77
+
78
+ headers = result_set["headers"]
79
+ rows = result_set["rowSet"]
80
+ return Collection.new unless headers && rows
81
+
82
+ records = rows.map { |row| build_historical_record(headers, row) }
83
+ Collection.new(records)
84
+ end
85
+ private_class_method :parse_history_response
86
+
87
+ # Finds the specified result set in the response
88
+ # @api private
89
+ # @return [Hash, nil] the result set hash
90
+ def self.find_result_set(data, name)
91
+ result_sets = data["resultSets"]
92
+ return unless result_sets
93
+
94
+ result_sets.find { |rs| rs["name"].eql?(name) }
95
+ end
96
+ private_class_method :find_result_set
97
+
98
+ # Builds a TeamDetail object from raw data
99
+ # @api private
100
+ # @return [TeamDetail] the team detail object
101
+ def self.build_team_detail(headers, row)
102
+ data = headers.zip(row).to_h
103
+ TeamDetail.new(**detail_attributes(data))
104
+ end
105
+ private_class_method :build_team_detail
106
+
107
+ # Builds a TeamHistoricalRecord object from raw data
108
+ # @api private
109
+ # @return [TeamHistoricalRecord] the historical record object
110
+ def self.build_historical_record(headers, row)
111
+ data = headers.zip(row).to_h
112
+ TeamHistoricalRecord.new(**history_attributes(data))
113
+ end
114
+ private_class_method :build_historical_record
115
+
116
+ # Extracts team detail attributes from data
117
+ # @api private
118
+ # @return [Hash] detail attributes
119
+ def self.detail_attributes(data)
120
+ {team_id: data.fetch("TEAM_ID"), abbreviation: data.fetch("ABBREVIATION"),
121
+ nickname: data.fetch("NICKNAME"), year_founded: data.fetch("YEARFOUNDED"),
122
+ city: data.fetch("CITY"), arena: data.fetch("ARENA"),
123
+ arena_capacity: data.fetch("ARENACAPACITY"), owner: data.fetch("OWNER"),
124
+ general_manager: data.fetch("GENERALMANAGER"), head_coach: data.fetch("HEADCOACH"),
125
+ d_league_affiliation: data.fetch("DLEAGUEAFFILIATION")}
126
+ end
127
+ private_class_method :detail_attributes
128
+
129
+ # Combines all history attributes
130
+ # @api private
131
+ # @return [Hash] the combined attributes
132
+ def self.history_attributes(data)
133
+ identity_history_attributes(data).merge(record_attributes(data), playoff_attributes(data))
134
+ end
135
+ private_class_method :history_attributes
136
+
137
+ # Extracts identity history attributes from data
138
+ # @api private
139
+ # @return [Hash] identity history attributes
140
+ def self.identity_history_attributes(data)
141
+ {team_id: data.fetch("TEAM_ID"), city: data.fetch("CITY"), nickname: data.fetch("NICKNAME"),
142
+ season_id: data.fetch("SEASON_ID"), year: data.fetch("YEAR")}
143
+ end
144
+ private_class_method :identity_history_attributes
145
+
146
+ # Extracts record attributes from data
147
+ # @api private
148
+ # @return [Hash] record attributes
149
+ def self.record_attributes(data)
150
+ {wins: data.fetch("WINS"), losses: data.fetch("LOSSES"), win_pct: data.fetch("WIN_PCT"),
151
+ conf_rank: data.fetch("CONF_RANK"), div_rank: data.fetch("DIV_RANK")}
152
+ end
153
+ private_class_method :record_attributes
154
+
155
+ # Extracts playoff attributes from data
156
+ # @api private
157
+ # @return [Hash] playoff attributes
158
+ def self.playoff_attributes(data)
159
+ {po_wins: data.fetch("PO_WINS"), po_losses: data.fetch("PO_LOSSES"),
160
+ conf_count: data.fetch("CONF_COUNT"), div_count: data.fetch("DIV_COUNT"),
161
+ nba_finals_appearance: data.fetch("NBA_FINALS_APPEARANCE")}
162
+ end
163
+ private_class_method :playoff_attributes
164
+
165
+ # Extracts team ID from team object or integer
166
+ # @api private
167
+ # @return [Integer] the team ID
168
+ def self.extract_team_id(team)
169
+ team.instance_of?(Team) ? team.id : team
170
+ end
171
+ private_class_method :extract_team_id
172
+ end
173
+ end
@@ -0,0 +1,91 @@
1
+ require_relative "client"
2
+ require_relative "collection"
3
+ require_relative "response_parser"
4
+ require_relative "utils"
5
+
6
+ require_relative "team_estimated_metrics_stat"
7
+
8
+ module NBA
9
+ # Provides methods to retrieve team estimated metrics
10
+ #
11
+ # @api public
12
+ module TeamEstimatedMetrics
13
+ # Season type constant for regular season
14
+ # @return [String] the season type
15
+ REGULAR_SEASON = "Regular Season".freeze
16
+
17
+ # Season type constant for playoffs
18
+ # @return [String] the season type
19
+ PLAYOFFS = "Playoffs".freeze
20
+
21
+ # Result set name for team estimated metrics
22
+ # @return [String] the result set name
23
+ RESULT_SET_NAME = "TeamEstimatedMetrics".freeze
24
+
25
+ # Retrieves estimated metrics for all teams
26
+ #
27
+ # @api public
28
+ # @example
29
+ # stats = NBA::TeamEstimatedMetrics.all
30
+ # stats.each { |s| puts "#{s.team_name}: #{s.e_net_rating} net rating" }
31
+ #
32
+ # @param season [Integer] the season year
33
+ # @param season_type [String] the season type
34
+ # @param client [Client] the API client to use
35
+ # @return [Collection] a collection of estimated metrics stats
36
+ def self.all(season: Utils.current_season, season_type: REGULAR_SEASON, client: CLIENT)
37
+ path = build_path(season, season_type)
38
+ ResponseParser.parse(client.get(path), result_set: RESULT_SET_NAME) { |data| build_stat(data) }
39
+ end
40
+
41
+ # Builds the API request path
42
+ #
43
+ # @api private
44
+ # @return [String] the request path
45
+ def self.build_path(season, season_type)
46
+ season_str = Utils.format_season(season)
47
+ "teamestimatedmetrics?LeagueID=00&Season=#{season_str}&SeasonType=#{season_type}"
48
+ end
49
+ private_class_method :build_path
50
+
51
+ # Builds an estimated metrics stat from API data
52
+ #
53
+ # @api private
54
+ # @return [TeamEstimatedMetricsStat]
55
+ def self.build_stat(data)
56
+ TeamEstimatedMetricsStat.new(**identity_info(data), **rating_info(data), **percentage_info(data))
57
+ end
58
+ private_class_method :build_stat
59
+
60
+ # Extracts identity information from data
61
+ #
62
+ # @api private
63
+ # @return [Hash]
64
+ def self.identity_info(data)
65
+ {team_id: data["TEAM_ID"], team_name: data["TEAM_NAME"],
66
+ gp: data["GP"], w: data["W"], l: data["L"],
67
+ w_pct: data["W_PCT"], min: data["MIN"]}
68
+ end
69
+ private_class_method :identity_info
70
+
71
+ # Extracts rating information from data
72
+ #
73
+ # @api private
74
+ # @return [Hash]
75
+ def self.rating_info(data)
76
+ {e_off_rating: data["E_OFF_RATING"], e_def_rating: data["E_DEF_RATING"],
77
+ e_net_rating: data["E_NET_RATING"], e_pace: data["E_PACE"], e_ast_ratio: data["E_AST_RATIO"]}
78
+ end
79
+ private_class_method :rating_info
80
+
81
+ # Extracts percentage information from data
82
+ #
83
+ # @api private
84
+ # @return [Hash]
85
+ def self.percentage_info(data)
86
+ {e_oreb_pct: data["E_OREB_PCT"], e_dreb_pct: data["E_DREB_PCT"],
87
+ e_reb_pct: data["E_REB_PCT"], e_tm_tov_pct: data["E_TM_TOV_PCT"]}
88
+ end
89
+ private_class_method :percentage_info
90
+ end
91
+ end
@@ -0,0 +1,146 @@
1
+ module NBA
2
+ # Represents team estimated metrics
3
+ #
4
+ # @api public
5
+ class TeamEstimatedMetricsStat < Shale::Mapper
6
+ include Equalizer.new(:team_id)
7
+
8
+ # @!attribute [rw] team_id
9
+ # Returns the team ID
10
+ # @api public
11
+ # @example
12
+ # stat.team_id #=> 1610612744
13
+ # @return [Integer] the team ID
14
+ attribute :team_id, Shale::Type::Integer
15
+
16
+ # @!attribute [rw] team_name
17
+ # Returns the team name
18
+ # @api public
19
+ # @example
20
+ # stat.team_name #=> "Golden State Warriors"
21
+ # @return [String] the team name
22
+ attribute :team_name, Shale::Type::String
23
+
24
+ # @!attribute [rw] gp
25
+ # Returns games played
26
+ # @api public
27
+ # @example
28
+ # stat.gp #=> 82
29
+ # @return [Integer] games played
30
+ attribute :gp, Shale::Type::Integer
31
+
32
+ # @!attribute [rw] w
33
+ # Returns wins
34
+ # @api public
35
+ # @example
36
+ # stat.w #=> 46
37
+ # @return [Integer] wins
38
+ attribute :w, Shale::Type::Integer
39
+
40
+ # @!attribute [rw] l
41
+ # Returns losses
42
+ # @api public
43
+ # @example
44
+ # stat.l #=> 36
45
+ # @return [Integer] losses
46
+ attribute :l, Shale::Type::Integer
47
+
48
+ # @!attribute [rw] w_pct
49
+ # Returns win percentage
50
+ # @api public
51
+ # @example
52
+ # stat.w_pct #=> 0.561
53
+ # @return [Float] win percentage
54
+ attribute :w_pct, Shale::Type::Float
55
+
56
+ # @!attribute [rw] min
57
+ # Returns minutes per game
58
+ # @api public
59
+ # @example
60
+ # stat.min #=> 48.0
61
+ # @return [Float] minutes
62
+ attribute :min, Shale::Type::Float
63
+
64
+ # @!attribute [rw] e_off_rating
65
+ # Returns estimated offensive rating
66
+ # @api public
67
+ # @example
68
+ # stat.e_off_rating #=> 117.5
69
+ # @return [Float] estimated offensive rating
70
+ attribute :e_off_rating, Shale::Type::Float
71
+
72
+ # @!attribute [rw] e_def_rating
73
+ # Returns estimated defensive rating
74
+ # @api public
75
+ # @example
76
+ # stat.e_def_rating #=> 110.2
77
+ # @return [Float] estimated defensive rating
78
+ attribute :e_def_rating, Shale::Type::Float
79
+
80
+ # @!attribute [rw] e_net_rating
81
+ # Returns estimated net rating
82
+ # @api public
83
+ # @example
84
+ # stat.e_net_rating #=> 7.3
85
+ # @return [Float] estimated net rating
86
+ attribute :e_net_rating, Shale::Type::Float
87
+
88
+ # @!attribute [rw] e_pace
89
+ # Returns estimated pace
90
+ # @api public
91
+ # @example
92
+ # stat.e_pace #=> 101.5
93
+ # @return [Float] estimated pace
94
+ attribute :e_pace, Shale::Type::Float
95
+
96
+ # @!attribute [rw] e_ast_ratio
97
+ # Returns estimated assist ratio
98
+ # @api public
99
+ # @example
100
+ # stat.e_ast_ratio #=> 18.5
101
+ # @return [Float] estimated assist ratio
102
+ attribute :e_ast_ratio, Shale::Type::Float
103
+
104
+ # @!attribute [rw] e_oreb_pct
105
+ # Returns estimated offensive rebound percentage
106
+ # @api public
107
+ # @example
108
+ # stat.e_oreb_pct #=> 25.5
109
+ # @return [Float] estimated offensive rebound percentage
110
+ attribute :e_oreb_pct, Shale::Type::Float
111
+
112
+ # @!attribute [rw] e_dreb_pct
113
+ # Returns estimated defensive rebound percentage
114
+ # @api public
115
+ # @example
116
+ # stat.e_dreb_pct #=> 75.5
117
+ # @return [Float] estimated defensive rebound percentage
118
+ attribute :e_dreb_pct, Shale::Type::Float
119
+
120
+ # @!attribute [rw] e_reb_pct
121
+ # Returns estimated rebound percentage
122
+ # @api public
123
+ # @example
124
+ # stat.e_reb_pct #=> 50.5
125
+ # @return [Float] estimated rebound percentage
126
+ attribute :e_reb_pct, Shale::Type::Float
127
+
128
+ # @!attribute [rw] e_tm_tov_pct
129
+ # Returns estimated team turnover percentage
130
+ # @api public
131
+ # @example
132
+ # stat.e_tm_tov_pct #=> 11.5
133
+ # @return [Float] estimated team turnover percentage
134
+ attribute :e_tm_tov_pct, Shale::Type::Float
135
+
136
+ # Returns the team object
137
+ #
138
+ # @api public
139
+ # @example
140
+ # stat.team #=> #<NBA::Team>
141
+ # @return [Team, nil] the team object
142
+ def team
143
+ Teams.find(team_id)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,143 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "utils"
5
+
6
+ require_relative "team_game_log_entry"
7
+
8
+ module NBA
9
+ # Provides methods to retrieve team game logs
10
+ module TeamGameLog
11
+ # Regular season type
12
+ # @return [String] the season type
13
+ REGULAR_SEASON = "Regular Season".freeze
14
+
15
+ # Playoffs season type
16
+ # @return [String] the season type
17
+ PLAYOFFS = "Playoffs".freeze
18
+
19
+ # Retrieves game logs for a team
20
+ #
21
+ # @api public
22
+ # @example
23
+ # logs = NBA::TeamGameLog.find(team: Team::GSW)
24
+ # logs.each { |log| puts "#{log.game_date}: #{log.pts} points" }
25
+ # @param team [Integer, Team] the team ID or Team object
26
+ # @param season [Integer] the season year (defaults to current season)
27
+ # @param season_type [String] the season type (Regular Season, Playoffs)
28
+ # @param client [Client] the API client to use
29
+ # @return [Collection] a collection of team game logs
30
+ def self.find(team:, season: Utils.current_season, season_type: REGULAR_SEASON, client: CLIENT)
31
+ team_id = extract_team_id(team)
32
+ season_str = Utils.format_season(season)
33
+ path = build_path(team_id, season_str, season_type)
34
+ response = client.get(path)
35
+ parse_response(response)
36
+ end
37
+
38
+ # Builds the API path for team game log
39
+ #
40
+ # @api private
41
+ # @param team_id [Integer] the team ID
42
+ # @param season_str [String] the season string
43
+ # @param season_type [String] the season type
44
+ # @return [String] the API path
45
+ def self.build_path(team_id, season_str, season_type)
46
+ encoded_type = season_type
47
+ "teamgamelog?TeamID=#{team_id}&Season=#{season_str}&SeasonType=#{encoded_type}"
48
+ end
49
+ private_class_method :build_path
50
+
51
+ # Parses the API response
52
+ #
53
+ # @api private
54
+ # @param response [String] the JSON response body
55
+ # @return [Collection] a collection of team game logs
56
+ def self.parse_response(response)
57
+ return Collection.new unless response
58
+
59
+ data = JSON.parse(response)
60
+ result_set = data.dig("resultSets", 0)
61
+ return Collection.new unless result_set
62
+
63
+ headers = result_set["headers"]
64
+ rows = result_set["rowSet"]
65
+ return Collection.new unless headers && rows
66
+
67
+ logs = rows.map { |row| build_team_game_log(headers, row) }
68
+ Collection.new(logs)
69
+ end
70
+ private_class_method :parse_response
71
+
72
+ # Builds a team game log from a row
73
+ #
74
+ # @api private
75
+ # @param headers [Array<String>] the column headers
76
+ # @param row [Array] the row data
77
+ # @return [TeamGameLogEntry] the team game log object
78
+ def self.build_team_game_log(headers, row)
79
+ data = headers.zip(row).to_h
80
+ TeamGameLogEntry.new(**team_game_log_attributes(data))
81
+ end
82
+ private_class_method :build_team_game_log
83
+
84
+ # Combines all team game log attributes
85
+ #
86
+ # @api private
87
+ # @param data [Hash] the game log data
88
+ # @return [Hash] the combined attributes
89
+ def self.team_game_log_attributes(data)
90
+ game_info_attributes(data).merge(shooting_attributes(data), counting_attributes(data))
91
+ end
92
+ private_class_method :team_game_log_attributes
93
+
94
+ # Extracts game info attributes
95
+ #
96
+ # @api private
97
+ # @param data [Hash] the game log data
98
+ # @return [Hash] the game info attributes
99
+ def self.game_info_attributes(data)
100
+ {team_id: data["Team_ID"], game_id: data["Game_ID"], game_date: data["GAME_DATE"],
101
+ matchup: data["MATCHUP"], wl: data["WL"], min: data["MIN"]}
102
+ end
103
+ private_class_method :game_info_attributes
104
+
105
+ # Extracts shooting attributes
106
+ #
107
+ # @api private
108
+ # @param data [Hash] the game log data
109
+ # @return [Hash] the shooting attributes
110
+ def self.shooting_attributes(data)
111
+ {fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
112
+ fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"],
113
+ ftm: data["FTM"], fta: data["FTA"], ft_pct: data["FT_PCT"]}
114
+ end
115
+ private_class_method :shooting_attributes
116
+
117
+ # Extracts counting stats attributes
118
+ #
119
+ # @api private
120
+ # @param data [Hash] the game log data
121
+ # @return [Hash] the counting stats attributes
122
+ def self.counting_attributes(data)
123
+ {oreb: data["OREB"], dreb: data["DREB"], reb: data["REB"],
124
+ ast: data["AST"], stl: data["STL"], blk: data["BLK"],
125
+ tov: data["TOV"], pf: data["PF"], pts: data["PTS"],
126
+ plus_minus: data["PLUS_MINUS"]}
127
+ end
128
+ private_class_method :counting_attributes
129
+
130
+ # Extracts team ID from a Team object or returns the integer
131
+ #
132
+ # @api private
133
+ # @param team [Team, Integer] the team or team ID
134
+ # @return [Integer] the team ID
135
+ def self.extract_team_id(team)
136
+ case team
137
+ when Team then team.id
138
+ else team
139
+ end
140
+ end
141
+ private_class_method :extract_team_id
142
+ end
143
+ end