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,275 @@
1
+ require "equalizer"
2
+ require "shale"
3
+
4
+ module NBA
5
+ # Represents league-wide team statistics
6
+ class LeagueDashTeamStat < Shale::Mapper
7
+ include Equalizer.new(:team_id, :season_id)
8
+
9
+ # @!attribute [rw] team_id
10
+ # Returns the team ID
11
+ # @api public
12
+ # @example
13
+ # stat.team_id #=> 1610612744
14
+ # @return [Integer] the team ID
15
+ attribute :team_id, Shale::Type::Integer
16
+
17
+ # @!attribute [rw] team_name
18
+ # Returns the team name
19
+ # @api public
20
+ # @example
21
+ # stat.team_name #=> "Golden State Warriors"
22
+ # @return [String] the team name
23
+ attribute :team_name, Shale::Type::String
24
+
25
+ # @!attribute [rw] season_id
26
+ # Returns the season ID
27
+ # @api public
28
+ # @example
29
+ # stat.season_id #=> "2024-25"
30
+ # @return [String] the season ID
31
+ attribute :season_id, Shale::Type::String
32
+
33
+ # @!attribute [rw] gp
34
+ # Returns games played
35
+ # @api public
36
+ # @example
37
+ # stat.gp #=> 82
38
+ # @return [Integer] games played
39
+ attribute :gp, Shale::Type::Integer
40
+
41
+ # @!attribute [rw] w
42
+ # Returns wins
43
+ # @api public
44
+ # @example
45
+ # stat.w #=> 53
46
+ # @return [Integer] wins
47
+ attribute :w, Shale::Type::Integer
48
+
49
+ # @!attribute [rw] l
50
+ # Returns losses
51
+ # @api public
52
+ # @example
53
+ # stat.l #=> 29
54
+ # @return [Integer] losses
55
+ attribute :l, Shale::Type::Integer
56
+
57
+ # @!attribute [rw] w_pct
58
+ # Returns win percentage
59
+ # @api public
60
+ # @example
61
+ # stat.w_pct #=> 0.646
62
+ # @return [Float] win percentage
63
+ attribute :w_pct, Shale::Type::Float
64
+
65
+ # @!attribute [rw] min
66
+ # Returns minutes per game
67
+ # @api public
68
+ # @example
69
+ # stat.min #=> 240.0
70
+ # @return [Float] minutes per game
71
+ attribute :min, Shale::Type::Float
72
+
73
+ # @!attribute [rw] fgm
74
+ # Returns field goals made per game
75
+ # @api public
76
+ # @example
77
+ # stat.fgm #=> 42.3
78
+ # @return [Float] field goals made
79
+ attribute :fgm, Shale::Type::Float
80
+
81
+ # @!attribute [rw] fga
82
+ # Returns field goals attempted per game
83
+ # @api public
84
+ # @example
85
+ # stat.fga #=> 90.5
86
+ # @return [Float] field goals attempted
87
+ attribute :fga, Shale::Type::Float
88
+
89
+ # @!attribute [rw] fg_pct
90
+ # Returns field goal percentage
91
+ # @api public
92
+ # @example
93
+ # stat.fg_pct #=> 0.467
94
+ # @return [Float] field goal percentage
95
+ attribute :fg_pct, Shale::Type::Float
96
+
97
+ # @!attribute [rw] fg3m
98
+ # Returns three pointers made per game
99
+ # @api public
100
+ # @example
101
+ # stat.fg3m #=> 13.7
102
+ # @return [Float] three pointers made
103
+ attribute :fg3m, Shale::Type::Float
104
+
105
+ # @!attribute [rw] fg3a
106
+ # Returns three pointers attempted per game
107
+ # @api public
108
+ # @example
109
+ # stat.fg3a #=> 38.2
110
+ # @return [Float] three pointers attempted
111
+ attribute :fg3a, Shale::Type::Float
112
+
113
+ # @!attribute [rw] fg3_pct
114
+ # Returns three point percentage
115
+ # @api public
116
+ # @example
117
+ # stat.fg3_pct #=> 0.359
118
+ # @return [Float] three point percentage
119
+ attribute :fg3_pct, Shale::Type::Float
120
+
121
+ # @!attribute [rw] ftm
122
+ # Returns free throws made per game
123
+ # @api public
124
+ # @example
125
+ # stat.ftm #=> 17.5
126
+ # @return [Float] free throws made
127
+ attribute :ftm, Shale::Type::Float
128
+
129
+ # @!attribute [rw] fta
130
+ # Returns free throws attempted per game
131
+ # @api public
132
+ # @example
133
+ # stat.fta #=> 22.3
134
+ # @return [Float] free throws attempted
135
+ attribute :fta, Shale::Type::Float
136
+
137
+ # @!attribute [rw] ft_pct
138
+ # Returns free throw percentage
139
+ # @api public
140
+ # @example
141
+ # stat.ft_pct #=> 0.785
142
+ # @return [Float] free throw percentage
143
+ attribute :ft_pct, Shale::Type::Float
144
+
145
+ # @!attribute [rw] oreb
146
+ # Returns offensive rebounds per game
147
+ # @api public
148
+ # @example
149
+ # stat.oreb #=> 10.2
150
+ # @return [Float] offensive rebounds
151
+ attribute :oreb, Shale::Type::Float
152
+
153
+ # @!attribute [rw] dreb
154
+ # Returns defensive rebounds per game
155
+ # @api public
156
+ # @example
157
+ # stat.dreb #=> 34.5
158
+ # @return [Float] defensive rebounds
159
+ attribute :dreb, Shale::Type::Float
160
+
161
+ # @!attribute [rw] reb
162
+ # Returns total rebounds per game
163
+ # @api public
164
+ # @example
165
+ # stat.reb #=> 44.7
166
+ # @return [Float] total rebounds
167
+ attribute :reb, Shale::Type::Float
168
+
169
+ # @!attribute [rw] ast
170
+ # Returns assists per game
171
+ # @api public
172
+ # @example
173
+ # stat.ast #=> 27.8
174
+ # @return [Float] assists
175
+ attribute :ast, Shale::Type::Float
176
+
177
+ # @!attribute [rw] tov
178
+ # Returns turnovers per game
179
+ # @api public
180
+ # @example
181
+ # stat.tov #=> 13.2
182
+ # @return [Float] turnovers
183
+ attribute :tov, Shale::Type::Float
184
+
185
+ # @!attribute [rw] stl
186
+ # Returns steals per game
187
+ # @api public
188
+ # @example
189
+ # stat.stl #=> 7.5
190
+ # @return [Float] steals
191
+ attribute :stl, Shale::Type::Float
192
+
193
+ # @!attribute [rw] blk
194
+ # Returns blocks per game
195
+ # @api public
196
+ # @example
197
+ # stat.blk #=> 5.2
198
+ # @return [Float] blocks
199
+ attribute :blk, Shale::Type::Float
200
+
201
+ # @!attribute [rw] blka
202
+ # Returns blocked attempts per game
203
+ # @api public
204
+ # @example
205
+ # stat.blka #=> 4.8
206
+ # @return [Float] blocked attempts
207
+ attribute :blka, Shale::Type::Float
208
+
209
+ # @!attribute [rw] pf
210
+ # Returns personal fouls per game
211
+ # @api public
212
+ # @example
213
+ # stat.pf #=> 18.5
214
+ # @return [Float] personal fouls
215
+ attribute :pf, Shale::Type::Float
216
+
217
+ # @!attribute [rw] pfd
218
+ # Returns personal fouls drawn per game
219
+ # @api public
220
+ # @example
221
+ # stat.pfd #=> 19.2
222
+ # @return [Float] personal fouls drawn
223
+ attribute :pfd, Shale::Type::Float
224
+
225
+ # @!attribute [rw] pts
226
+ # Returns points per game
227
+ # @api public
228
+ # @example
229
+ # stat.pts #=> 115.8
230
+ # @return [Float] points
231
+ attribute :pts, Shale::Type::Float
232
+
233
+ # @!attribute [rw] plus_minus
234
+ # Returns plus/minus per game
235
+ # @api public
236
+ # @example
237
+ # stat.plus_minus #=> 5.2
238
+ # @return [Float] plus/minus
239
+ attribute :plus_minus, Shale::Type::Float
240
+
241
+ # @!attribute [rw] gp_rank
242
+ # Returns games played rank
243
+ # @api public
244
+ # @example
245
+ # stat.gp_rank #=> 1
246
+ # @return [Integer] games played rank
247
+ attribute :gp_rank, Shale::Type::Integer
248
+
249
+ # @!attribute [rw] w_rank
250
+ # Returns wins rank
251
+ # @api public
252
+ # @example
253
+ # stat.w_rank #=> 3
254
+ # @return [Integer] wins rank
255
+ attribute :w_rank, Shale::Type::Integer
256
+
257
+ # @!attribute [rw] pts_rank
258
+ # Returns points rank
259
+ # @api public
260
+ # @example
261
+ # stat.pts_rank #=> 5
262
+ # @return [Integer] points rank
263
+ attribute :pts_rank, Shale::Type::Integer
264
+
265
+ # Returns the team object
266
+ #
267
+ # @api public
268
+ # @example
269
+ # stat.team #=> #<NBA::Team>
270
+ # @return [Team, nil] the team object
271
+ def team
272
+ Teams.find(team_id)
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,172 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "league_dash_team_stat"
5
+ require_relative "utils"
6
+
7
+ module NBA
8
+ # Provides methods to retrieve league-wide team statistics
9
+ module LeagueDashTeamStats
10
+ # Result set name
11
+ # @return [String] the result set name
12
+ LEAGUE_DASH_TEAM_STATS = "LeagueDashTeamStats".freeze
13
+
14
+ # Regular season type
15
+ # @return [String] the season type
16
+ REGULAR_SEASON = "Regular Season".freeze
17
+
18
+ # Playoffs season type
19
+ # @return [String] the season type
20
+ PLAYOFFS = "Playoffs".freeze
21
+
22
+ # Per game mode
23
+ # @return [String] the per mode
24
+ PER_GAME = "PerGame".freeze
25
+
26
+ # Totals mode
27
+ # @return [String] the per mode
28
+ TOTALS = "Totals".freeze
29
+
30
+ # Per 100 possessions mode
31
+ # @return [String] the per mode
32
+ PER_100 = "Per100Possessions".freeze
33
+
34
+ # Retrieves league-wide team statistics
35
+ #
36
+ # @api public
37
+ # @example
38
+ # stats = NBA::LeagueDashTeamStats.all(season: 2024)
39
+ # stats.each { |s| puts "#{s.team_name}: #{s.pts} PPG" }
40
+ # @param season [Integer] the season year (defaults to current season)
41
+ # @param season_type [String] the season type (Regular Season, Playoffs)
42
+ # @param per_mode [String] the per mode (PerGame, Totals, Per100Possessions)
43
+ # @param client [Client] the API client to use
44
+ # @return [Collection] a collection of team stats
45
+ def self.all(season: Utils.current_season, season_type: REGULAR_SEASON, per_mode: PER_GAME, client: CLIENT)
46
+ path = build_path(season, season_type, per_mode)
47
+ response = client.get(path)
48
+ parse_response(response, season)
49
+ end
50
+
51
+ # Builds the API path
52
+ # @api private
53
+ # @param season [Integer] the season
54
+ # @param season_type [String] the season type
55
+ # @param per_mode [String] the per mode
56
+ # @return [String] the path
57
+ def self.build_path(season, season_type, per_mode)
58
+ "leaguedashteamstats?Conference=&DateFrom=&DateTo=&Division=&GameScope=&GameSegment=&Height=&" \
59
+ "ISTRound=&LastNGames=0&LeagueID=00&Location=&MeasureType=Base&Month=0&OpponentTeamID=0&Outcome=&" \
60
+ "PORound=0&PaceAdjust=N&PerMode=#{per_mode}&Period=0&PlayerExperience=&PlayerPosition=&PlusMinus=N&" \
61
+ "Rank=Y&Season=#{Utils.format_season(season)}&SeasonSegment=&SeasonType=#{season_type}&ShotClockRange=&" \
62
+ "StarterBench=&TeamID=0&TwoWay=0&VsConference=&VsDivision="
63
+ end
64
+ private_class_method :build_path
65
+
66
+ # Parses the API response
67
+ # @api private
68
+ # @param response [String, nil] the JSON response
69
+ # @param season [Integer] the season
70
+ # @return [Collection] collection of team stats
71
+ def self.parse_response(response, season)
72
+ return Collection.new unless response
73
+
74
+ data = JSON.parse(response)
75
+ result_set = find_result_set(data)
76
+ return Collection.new unless result_set
77
+
78
+ build_team_stats(result_set, Utils.format_season(season))
79
+ end
80
+ private_class_method :parse_response
81
+
82
+ # Finds the result set
83
+ # @api private
84
+ # @param data [Hash] the parsed JSON
85
+ # @return [Hash, nil] the result set
86
+ def self.find_result_set(data)
87
+ result_sets = data["resultSets"]
88
+ return unless result_sets
89
+
90
+ result_sets.find { |rs| rs.fetch("name").eql?(LEAGUE_DASH_TEAM_STATS) }
91
+ end
92
+ private_class_method :find_result_set
93
+
94
+ # Builds team stats collection
95
+ # @api private
96
+ # @param result_set [Hash] the result set
97
+ # @param season_id [String] the season ID
98
+ # @return [Collection] collection of team stats
99
+ def self.build_team_stats(result_set, season_id)
100
+ headers = result_set["headers"]
101
+ rows = result_set["rowSet"]
102
+ return Collection.new unless headers && rows
103
+
104
+ stats = rows.map { |row| build_team_stat(headers, row, season_id) }
105
+ Collection.new(stats)
106
+ end
107
+ private_class_method :build_team_stats
108
+
109
+ # Builds a single team stat
110
+ # @api private
111
+ # @param headers [Array<String>] the headers
112
+ # @param row [Array] the row data
113
+ # @param season_id [String] the season ID
114
+ # @return [LeagueDashTeamStat] the team stat
115
+ def self.build_team_stat(headers, row, season_id)
116
+ data = headers.zip(row).to_h
117
+ LeagueDashTeamStat.new(**team_stat_attributes(data, season_id))
118
+ end
119
+ private_class_method :build_team_stat
120
+
121
+ # Combines all team stat attributes
122
+ # @api private
123
+ # @param data [Hash] the raw data
124
+ # @param season_id [String] the season ID
125
+ # @return [Hash] the combined attributes
126
+ def self.team_stat_attributes(data, season_id)
127
+ identity_attributes(data, season_id).merge(shooting_attributes(data), counting_attributes(data), rank_attributes(data))
128
+ end
129
+ private_class_method :team_stat_attributes
130
+
131
+ # Extracts identity attributes
132
+ # @api private
133
+ # @param data [Hash] the raw data
134
+ # @param season_id [String] the season ID
135
+ # @return [Hash] identity attributes
136
+ def self.identity_attributes(data, season_id)
137
+ {team_id: data.fetch("TEAM_ID"), team_name: data.fetch("TEAM_NAME"), season_id: season_id,
138
+ gp: data.fetch("GP"), w: data.fetch("W"), l: data.fetch("L"), w_pct: data.fetch("W_PCT"), min: data.fetch("MIN")}
139
+ end
140
+ private_class_method :identity_attributes
141
+
142
+ # Extracts shooting attributes
143
+ # @api private
144
+ # @param data [Hash] the raw data
145
+ # @return [Hash] shooting attributes
146
+ def self.shooting_attributes(data)
147
+ {fgm: data.fetch("FGM"), fga: data.fetch("FGA"), fg_pct: data.fetch("FG_PCT"), fg3m: data.fetch("FG3M"), fg3a: data.fetch("FG3A"),
148
+ fg3_pct: data.fetch("FG3_PCT"), ftm: data.fetch("FTM"), fta: data.fetch("FTA"), ft_pct: data.fetch("FT_PCT")}
149
+ end
150
+ private_class_method :shooting_attributes
151
+
152
+ # Extracts counting attributes
153
+ # @api private
154
+ # @param data [Hash] the raw data
155
+ # @return [Hash] counting attributes
156
+ def self.counting_attributes(data)
157
+ {oreb: data.fetch("OREB"), dreb: data.fetch("DREB"), reb: data.fetch("REB"), ast: data.fetch("AST"), tov: data.fetch("TOV"),
158
+ stl: data.fetch("STL"), blk: data.fetch("BLK"), blka: data.fetch("BLKA"), pf: data.fetch("PF"), pfd: data.fetch("PFD"),
159
+ pts: data.fetch("PTS"), plus_minus: data.fetch("PLUS_MINUS")}
160
+ end
161
+ private_class_method :counting_attributes
162
+
163
+ # Extracts rank attributes
164
+ # @api private
165
+ # @param data [Hash] the raw data
166
+ # @return [Hash] rank attributes
167
+ def self.rank_attributes(data)
168
+ {gp_rank: data.fetch("GP_RANK"), w_rank: data.fetch("W_RANK"), pts_rank: data.fetch("PTS_RANK")}
169
+ end
170
+ private_class_method :rank_attributes
171
+ end
172
+ end
@@ -0,0 +1,170 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "utils"
5
+
6
+ require_relative "found_game"
7
+
8
+ module NBA
9
+ # Provides methods to find games based on criteria
10
+ module LeagueGameFinder
11
+ # Result set name for team games
12
+ # @return [String] the result set name
13
+ TEAM_GAMES = "TeamGameFinderResults".freeze
14
+
15
+ # Result set name for player games
16
+ # @return [String] the result set name
17
+ PLAYER_GAMES = "PlayerGameFinderResults".freeze
18
+
19
+ # Season type constant for regular season
20
+ # @return [String] the season type
21
+ REGULAR_SEASON = "Regular Season".freeze
22
+
23
+ # Season type constant for playoffs
24
+ # @return [String] the season type
25
+ PLAYOFFS = "Playoffs".freeze
26
+
27
+ # Finds games for a team
28
+ #
29
+ # @api public
30
+ # @example
31
+ # games = NBA::LeagueGameFinder.by_team(team: NBA::Team::GSW)
32
+ # games.each { |g| puts "#{g.game_date}: #{g.matchup} - #{g.wl}" }
33
+ # @param team [Integer, Team] the team ID or Team object
34
+ # @param season [Integer, nil] the season year (nil for all seasons)
35
+ # @param season_type [String] the season type
36
+ # @param client [Client] the API client to use
37
+ # @return [Collection] a collection of found games
38
+ def self.by_team(team:, season: nil, season_type: REGULAR_SEASON, client: CLIENT)
39
+ team_id = Utils.extract_id(team)
40
+ path = build_team_path(team_id, season, season_type)
41
+ response = client.get(path)
42
+ parse_response(response, TEAM_GAMES)
43
+ end
44
+
45
+ # Finds games for a player
46
+ #
47
+ # @api public
48
+ # @example
49
+ # games = NBA::LeagueGameFinder.by_player(player: 201939)
50
+ # games.each { |g| puts "#{g.game_date}: #{g.matchup} - #{g.pts} pts" }
51
+ # @param player [Integer, Player] the player ID or Player object
52
+ # @param season [Integer, nil] the season year (nil for all seasons)
53
+ # @param season_type [String] the season type
54
+ # @param client [Client] the API client to use
55
+ # @return [Collection] a collection of found games
56
+ def self.by_player(player:, season: nil, season_type: REGULAR_SEASON, client: CLIENT)
57
+ player_id = Utils.extract_id(player)
58
+ path = build_player_path(player_id, season, season_type)
59
+ response = client.get(path)
60
+ parse_response(response, PLAYER_GAMES)
61
+ end
62
+
63
+ # Builds the API path for team game finder
64
+ #
65
+ # @api private
66
+ # @return [String] the request path
67
+ def self.build_team_path(team_id, season, season_type)
68
+ path = "leaguegamefinder?TeamID=#{team_id}&SeasonType=#{season_type}&LeagueID=00"
69
+ path += "&Season=#{Utils.format_season(season)}" if season
70
+ path
71
+ end
72
+ private_class_method :build_team_path
73
+
74
+ # Builds the API path for player game finder
75
+ #
76
+ # @api private
77
+ # @return [String] the request path
78
+ def self.build_player_path(player_id, season, season_type)
79
+ path = "leaguegamefinder?PlayerID=#{player_id}&SeasonType=#{season_type}&LeagueID=00"
80
+ path += "&Season=#{Utils.format_season(season)}" if season
81
+ path
82
+ end
83
+ private_class_method :build_player_path
84
+
85
+ # Parses the API response into found game objects
86
+ #
87
+ # @api private
88
+ # @return [Collection] collection of found games
89
+ def self.parse_response(response, result_set_name)
90
+ return Collection.new unless response
91
+
92
+ data = JSON.parse(response)
93
+ result_set = find_result_set(data, result_set_name)
94
+ return Collection.new unless result_set
95
+
96
+ headers = result_set["headers"]
97
+ rows = result_set["rowSet"]
98
+ return Collection.new unless headers && rows
99
+
100
+ games = rows.map { |row| build_found_game(headers, row) }
101
+ Collection.new(games)
102
+ end
103
+ private_class_method :parse_response
104
+
105
+ # Finds the result set in the response
106
+ #
107
+ # @api private
108
+ # @return [Hash, nil] the result set hash
109
+ def self.find_result_set(data, name)
110
+ result_sets = data["resultSets"]
111
+ return unless result_sets
112
+
113
+ result_sets.find { |rs| rs["name"].eql?(name) }
114
+ end
115
+ private_class_method :find_result_set
116
+
117
+ # Builds a FoundGame object from raw data
118
+ #
119
+ # @api private
120
+ # @return [FoundGame] the found game object
121
+ def self.build_found_game(headers, row)
122
+ data = headers.zip(row).to_h
123
+ FoundGame.new(**found_game_attributes(data))
124
+ end
125
+ private_class_method :build_found_game
126
+
127
+ # Combines all found game attributes
128
+ #
129
+ # @api private
130
+ # @return [Hash] the combined attributes
131
+ def self.found_game_attributes(data)
132
+ identity_attributes(data).merge(shooting_attributes(data), counting_attributes(data))
133
+ end
134
+ private_class_method :found_game_attributes
135
+
136
+ # Extracts identity attributes from data
137
+ #
138
+ # @api private
139
+ # @return [Hash] identity attributes
140
+ def self.identity_attributes(data)
141
+ {season_id: data["SEASON_ID"], team_id: data["TEAM_ID"],
142
+ team_abbreviation: data["TEAM_ABBREVIATION"], team_name: data["TEAM_NAME"],
143
+ game_id: data["GAME_ID"], game_date: data["GAME_DATE"],
144
+ matchup: data["MATCHUP"], wl: data["WL"], min: data["MIN"]}
145
+ end
146
+ private_class_method :identity_attributes
147
+
148
+ # Extracts shooting attributes from data
149
+ #
150
+ # @api private
151
+ # @return [Hash] shooting attributes
152
+ def self.shooting_attributes(data)
153
+ {fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
154
+ fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"],
155
+ ftm: data["FTM"], fta: data["FTA"], ft_pct: data["FT_PCT"]}
156
+ end
157
+ private_class_method :shooting_attributes
158
+
159
+ # Extracts counting stats attributes from data
160
+ #
161
+ # @api private
162
+ # @return [Hash] counting attributes
163
+ def self.counting_attributes(data)
164
+ {pts: data["PTS"], oreb: data["OREB"], dreb: data["DREB"], reb: data["REB"],
165
+ ast: data["AST"], stl: data["STL"], blk: data["BLK"],
166
+ tov: data["TOV"], pf: data["PF"], plus_minus: data["PLUS_MINUS"]}
167
+ end
168
+ private_class_method :counting_attributes
169
+ end
170
+ end