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