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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b953637ba9292b6414aec1db167b451df894d354
4
- data.tar.gz: 4d7ba14450b621e09958d41009d7e883a04ab6fb
2
+ SHA256:
3
+ metadata.gz: 0aa8e7be8eb8ce1f1833d33ea8e26d8d26fba4c2eb4d6068bfec951991477f2a
4
+ data.tar.gz: b561dcab1d4adfbcc111cf95e033929b351444737bb56821fc1a662b1addd8b4
5
5
  SHA512:
6
- metadata.gz: dc1baeadf0c937313ac2053e5c53758ee69f30713d6f772b5818ef673855275a20720452d573c21adb7ca04ac9d470253e54ba73a3f26a4d32e6828fa642fa35
7
- data.tar.gz: e8a6da21617c53615298400d32ef93f01633933c1ed5fbe4709c42358d9501ff31003a314b3b16941e71fe9ab84cf82cd90abdcf866959090e78c6fb66408cc6
6
+ metadata.gz: da2139f4a75911fe2237acb2412c1f0bbc2b45ac60f21e6f0b0954f2960295ea41347b0751c771b7fca0d8dda15193b5771177e2a7aed9500f4b10ed67e5ca3e
7
+ data.tar.gz: 10c7f5dec82e740a73216d0f121146fc7240537367274ac8a636be425c90264d9c9607a0246560e3d55c9d5ef6cd0ddf0116a18e3255b200d27f1d5c701e12ea
data/AGENTS.md ADDED
@@ -0,0 +1,362 @@
1
+ # CLAUDE.md
2
+
3
+ ## Project Overview
4
+
5
+ NBA Ruby is a Ruby interface to the NBA Stats API. It provides an idiomatic
6
+ Ruby wrapper around NBA's statistical data endpoints.
7
+
8
+ ## Development Commands
9
+
10
+ ```bash
11
+ bundle exec rake test # Run tests
12
+ bundle exec rake lint # Run RuboCop linter
13
+ bundle exec rake mutant # Run mutation testing (full suite)
14
+ bundle exec rake steep # Run type checker
15
+ bundle exec rake yard # Generate documentation
16
+ bundle exec rake # Run all quality checks
17
+ ```
18
+
19
+ ### Running Mutant for Individual Classes
20
+
21
+ Always run mutant on individual classes during development rather than the full
22
+ suite. The full mutant suite takes approximately 30 minutes to complete, so
23
+ instead execute more targeted mutant runs on classes you add or modify to
24
+ achieve 100% coverage.
25
+
26
+ ```bash
27
+ bundle exec mutant run --include lib --require nba --use minitest 'NBA::ClassName'
28
+ bundle exec mutant run --include lib --require nba --use minitest 'NBA::ClassName#method_name'
29
+ ```
30
+
31
+ ## Reference Libraries
32
+
33
+ This library should maintain:
34
+ - **Feature parity** with [nba_api](https://github.com/swar/nba_api) (Python)
35
+ - **Style consistency** with [mlb-ruby](https://github.com/sferik/mlb-ruby)
36
+
37
+ ## Code Style and Conventions
38
+
39
+ ### Fixing RuboCop Offenses
40
+
41
+ When asked to fix RuboCop offenses, **actually refactor the code to fix them.**
42
+ Never disable offenses, either inline with `# rubocop:disable` comments or in
43
+ `.rubocop.yml`. The goal is clean, idiomatic Ruby code that passes all linting
44
+ rules.
45
+
46
+ ### Internal Consistency is Critical
47
+
48
+ Before implementing any new feature, analyze existing similar features in the
49
+ codebase and follow the same patterns exactly. Look at:
50
+ - How similar API endpoints are implemented
51
+ - How data models are structured
52
+ - How tests are organized
53
+ - How documentation is written
54
+
55
+ ### One Class Per File
56
+
57
+ Each Ruby file should contain exactly one class or module. This applies to both
58
+ library code in `lib/` and test files in `test/`. When a test file has shared
59
+ helper classes or modules, extract them to a separate `*_test_helper.rb` file.
60
+
61
+ ### Parameter Naming
62
+
63
+ **Never use parameters ending in `_id` in public methods.** Instead:
64
+
65
+ ```ruby
66
+ # WRONG
67
+ def self.find(player_id:, client: CLIENT)
68
+ path = "endpoint?PlayerID=#{player_id}"
69
+ ...
70
+ end
71
+
72
+ # CORRECT
73
+ def self.find(player:, client: CLIENT)
74
+ id = Utils.extract_id(player)
75
+ path = "endpoint?PlayerID=#{id}"
76
+ ...
77
+ end
78
+ ```
79
+
80
+ Parameters should accept either:
81
+ - An ID (String or Integer)
82
+ - An object with an `id` method (e.g., `NBA::Player`, `NBA::Team`)
83
+
84
+ Use `Utils.extract_id(entity)` to normalize the value.
85
+
86
+ ### Predicate Methods
87
+
88
+ Convert boolean-like API responses to Ruby predicate methods:
89
+
90
+ ```ruby
91
+ # API returns "is_active" or boolean flags
92
+ def active?
93
+ is_active
94
+ end
95
+
96
+ # API returns "Y"/"N" strings
97
+ def greatest_75?
98
+ greatest_75_flag.eql?("Y")
99
+ end
100
+
101
+ # API returns numeric flags (1/0)
102
+ def win?
103
+ wl.eql?("W")
104
+ end
105
+
106
+ def loss?
107
+ wl.eql?("L")
108
+ end
109
+
110
+ # Shot made (1) or missed (0)
111
+ def made?
112
+ shot_made_flag.eql?(1)
113
+ end
114
+ ```
115
+
116
+ For enums with few options (win/loss, made/missed), provide predicate methods for each state.
117
+
118
+ ### Value Equality with `.eql?`
119
+
120
+ **Always use `.eql?` instead of `==`** when comparing values where both would produce the same result:
121
+
122
+ ```ruby
123
+ # WRONG - mutation testing will catch this
124
+ def win?
125
+ wl == "W"
126
+ end
127
+
128
+ # CORRECT - survives mutation testing
129
+ def win?
130
+ wl.eql?("W")
131
+ end
132
+ ```
133
+
134
+ This is required for mutation testing to verify the comparison is actually tested.
135
+
136
+ ### Type Annotations
137
+
138
+ **Keep all type annotations in `sig/nba.rbs`.** Never add inline type annotations
139
+ (like `#: -> String` or `# @type var`) in Ruby source files. Steep reads type
140
+ signatures from the RBS file, keeping the Ruby code clean and the types
141
+ centralized in one place.
142
+
143
+ ## Mutation Testing Requirements
144
+
145
+ **All new code must have 100% mutation coverage.** This requires specific testing patterns:
146
+
147
+ ### Testing Hash Key Access
148
+
149
+ When accessing data from a hash, write tests for both:
150
+ 1. When the key is present (returns the value)
151
+ 2. When the key is missing (returns nil or raises, depending on `fetch` vs `[]`)
152
+
153
+ ```ruby
154
+ # In the implementation
155
+ def self.build_player(data)
156
+ Player.new(
157
+ id: data.fetch("PERSON_ID"), # Required - raises if missing
158
+ nickname: data["NICKNAME"] # Optional - returns nil if missing
159
+ )
160
+ end
161
+
162
+ # In tests - test both present AND missing
163
+ def test_handles_missing_nickname_key
164
+ headers = all_headers.reject { |h| h == "NICKNAME" }
165
+ row = build_row_without("NICKNAME")
166
+ # ... stub request and assert attribute is nil
167
+ end
168
+ ```
169
+
170
+ ### Testing Predicate Methods
171
+
172
+ Test both true and false cases:
173
+
174
+ ```ruby
175
+ def test_win_returns_true_when_wl_is_w
176
+ log = GameLog.new(wl: "W")
177
+ assert_predicate log, :win?
178
+ end
179
+
180
+ def test_win_returns_false_when_wl_is_l
181
+ log = GameLog.new(wl: "L")
182
+ refute_predicate log, :win?
183
+ end
184
+ ```
185
+
186
+ ### Testing Value Equality
187
+
188
+ Test with equivalent but different types to ensure `.eql?` is used:
189
+
190
+ ```ruby
191
+ def test_made_uses_value_equality
192
+ shot = Shot.new(shot_made_flag: 1.0) # Float, not Integer
193
+ assert_predicate shot, :made?
194
+ end
195
+ ```
196
+
197
+ ### Killing Surviving Mutants
198
+
199
+ When mutant reports surviving mutants, kill them by either:
200
+
201
+ 1. **Adding tests** - Write a test that fails when the mutation is applied
202
+ 2. **Replacing with the mutation** - If the mutated code is equivalent or better, adopt it
203
+
204
+ **Never ignore or exclude code from mutation testing.** Do not:
205
+ - Add exclusions to `.mutant.yml`
206
+ - Use inline `# mutant:disable` comments
207
+ - Skip methods or classes from mutation coverage
208
+
209
+ If a mutant seems impossible to kill, the code is likely untestable or redundant—refactor it instead of excluding it.
210
+
211
+ ### Test Organization
212
+
213
+ Each test file must declare its coverage target:
214
+
215
+ ```ruby
216
+ module NBA
217
+ class MyFeatureTest < Minitest::Test
218
+ cover MyClass # Required for mutant coverage
219
+
220
+ def test_something
221
+ # ...
222
+ end
223
+ end
224
+ end
225
+ ```
226
+
227
+ ## Architecture Patterns
228
+
229
+ ### Data Models
230
+
231
+ All models inherit from `Shale::Mapper` and include `Equalizer`:
232
+
233
+ ```ruby
234
+ class Player < Shale::Mapper
235
+ include Equalizer.new(:id)
236
+
237
+ attribute :id, Shale::Type::Integer
238
+ attribute :full_name, Shale::Type::String
239
+
240
+ json do
241
+ map "PERSON_ID", to: :id
242
+ map "person_id", to: :id
243
+ map "PersonID", to: :id # Support multiple API formats
244
+ end
245
+ end
246
+ ```
247
+
248
+ ### Query Modules
249
+
250
+ API endpoints are implemented as module class methods:
251
+
252
+ ```ruby
253
+ module Players
254
+ def self.find(player, client: CLIENT)
255
+ id = Utils.extract_id(player)
256
+ return unless id
257
+
258
+ path = "commonplayerinfo?PlayerID=#{id}"
259
+ ResponseParser.parse_single(client.get(path)) { |data| build_player(data) }
260
+ end
261
+
262
+ def self.build_player(data)
263
+ Player.new(**identity_info(data), **physical_info(data))
264
+ end
265
+ private_class_method :build_player
266
+
267
+ def self.identity_info(data)
268
+ {id: data.fetch("PERSON_ID"), full_name: data.fetch("DISPLAY_FIRST_LAST")}
269
+ end
270
+ private_class_method :identity_info
271
+ end
272
+ ```
273
+
274
+ ### Collections
275
+
276
+ API methods returning multiple items return `Collection` objects (which are `Enumerable`).
277
+
278
+ ### Lazy Hydration
279
+
280
+ Related objects are fetched lazily via methods, not in constructors:
281
+
282
+ ```ruby
283
+ class Standing
284
+ def team
285
+ Teams.find(team_id)
286
+ end
287
+ end
288
+ ```
289
+
290
+ ## Documentation Requirements
291
+
292
+ All public methods require YARD documentation with 100% coverage:
293
+
294
+ ```ruby
295
+ # Returns whether the player is a Greatest 75 member
296
+ #
297
+ # @api public
298
+ # @example
299
+ # player.greatest_75? #=> true
300
+ # @return [Boolean] true if in Greatest 75
301
+ def greatest_75?
302
+ greatest_75_flag.eql?("Y")
303
+ end
304
+ ```
305
+
306
+ ## README Usage Examples
307
+
308
+ After implementing a new feature, add a usage example to the README. **Always
309
+ run the example code in a Ruby console to verify it works and produces the
310
+ expected output.**
311
+
312
+ ### Process
313
+
314
+ 1. Write the example code
315
+ 2. Run it in IRB or a script against the live API:
316
+ ```bash
317
+ bundle exec irb -r nba
318
+ ```
319
+ 3. Capture the actual output values
320
+ 4. Add the example to README.md with real, verified output
321
+
322
+ ### Example Format
323
+
324
+ Follow the existing README style with comments showing actual return values:
325
+
326
+ ```ruby
327
+ # Get player career stats
328
+ career = NBA::PlayerCareerStats.find(player: 201939)
329
+ career.size # => 16
330
+
331
+ season = career.last
332
+ season.pts # => 26.4
333
+ season.ast # => 6.1
334
+ ```
335
+
336
+ ### Why This Matters
337
+
338
+ - Examples with fabricated output erode user trust
339
+ - Live-tested examples catch API changes early
340
+ - Real data demonstrates actual library behavior
341
+ - Users can verify their setup works by comparing results
342
+
343
+ ### When to Update
344
+
345
+ - Adding a new endpoint or query module
346
+ - Adding new model attributes or methods
347
+ - Adding new predicate methods
348
+ - Changing existing API behavior
349
+
350
+ ## Quality Gates
351
+
352
+ All of these must pass before merging:
353
+ - `rake test` - 100% line and branch coverage
354
+ - `rake lint` - No RuboCop violations
355
+ - `rake mutant` - 100% mutation coverage (no surviving mutants)
356
+ - `rake steep` - No type errors
357
+ - `rake yardstick` - 100% documentation coverage
358
+
359
+ ## Plan Mode
360
+
361
+ - Make the plan extremely concise. Sacrifice grammar for the sake of concision.
362
+ - At the end of each plan, give me a list of unresolved questions to answer, if any.
data/CHANGELOG.md ADDED
@@ -0,0 +1,169 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
+
7
+ ## [0.2.0] - 2025-01-16
8
+
9
+ ### Added
10
+ - Core domain objects: Player, Team, Conference, Division, Position
11
+ - Collection class for handling groups of objects
12
+ - Client and Connection classes for API access
13
+ - Utility functions for common operations
14
+ - Full test coverage with Minitest
15
+ - Mutation testing with Mutant
16
+ - Type checking with Steep
17
+ - Documentation with YARD
18
+ - Code quality checks with RuboCop and Standard
19
+ - Uses Shale for JSON mapping
20
+ - Uses Equalizer for object equality
21
+
22
+ #### Command-Line Interface
23
+ - `nba` CLI tool for quick access to NBA data from the terminal
24
+ - Commands: `games`, `teams`, `player`, `standings`, `leaders`, `schedule`, `roster`
25
+ - Date filtering, conference filtering, and season selection options
26
+
27
+ #### Player Endpoints
28
+ - `CommonPlayerInfo` - Detailed player biography and career info
29
+ - `PlayerIndex` - Search and list all players
30
+ - `PlayerCareerStats` - Season-by-season career statistics
31
+ - `PlayerGameLog` / `PlayerGameLogs` - Game-by-game player stats
32
+ - `PlayerNextNGames` - Upcoming games for a player
33
+ - `PlayerProfileV2` - Comprehensive player profile data
34
+ - `PlayerAwards` - Career awards and accolades
35
+ - `PlayerCompare` - Head-to-head player comparisons
36
+ - `PlayerDashboard` - Player dashboard statistics
37
+ - `PlayerEstimatedMetrics` - Advanced estimated metrics (EPM, etc.)
38
+ - `PlayerGameStreakFinder` - Find player game streaks
39
+ - `PlayerDashPtPass` - Player tracking passing stats
40
+ - `PlayerDashPtReb` - Player tracking rebounding stats
41
+ - `PlayerDashPtShotDefend` - Player tracking defensive stats
42
+ - `PlayerDashPtShots` - Player tracking shooting stats
43
+ - `PlayerFantasyProfileBarGraph` - Fantasy basketball profile
44
+ - `PlayerVsPlayer` - Player vs player matchup stats
45
+ - `PlayerCareerByCollege` / `PlayerCareerByCollegeRollup` - Stats by college
46
+
47
+ #### Team Endpoints
48
+ - `TeamDetails` - Team info including arena, owner, GM, coach
49
+ - `TeamDashboard` - Team dashboard statistics
50
+ - `TeamInfoCommon` - Common team information and season ranks
51
+ - `TeamEstimatedMetrics` - Advanced team metrics
52
+ - `TeamHistoricalLeaders` - All-time team statistical leaders
53
+ - `TeamGameStreakFinder` - Find team game streaks
54
+ - `TeamDashPtPass` - Team tracking passing stats
55
+ - `TeamDashPtReb` - Team tracking rebounding stats
56
+ - `TeamDashPtShots` - Team tracking shooting stats
57
+ - `TeamPlayerDashboard` - Player stats within team context
58
+ - `TeamPlayerOnOffDetails` / `TeamPlayerOnOffSummary` - On/off court analysis
59
+ - `TeamVsPlayer` - Team performance vs specific players
60
+ - `TeamAndPlayersVsPlayers` - Team and players vs players matchups
61
+ - `TeamGameLog` / `TeamGameLogs` - Game-by-game team stats
62
+ - `TeamYearByYearStats` - Historical team stats by season
63
+ - `CommonTeamYears` - Team history timeline
64
+
65
+ #### Box Score Endpoints
66
+ - `BoxScoreTraditional` / `BoxScoreTraditionalV3` - Traditional stats
67
+ - `BoxScoreAdvanced` / `BoxScoreAdvancedV3` - Advanced stats (eFG%, TS%, etc.)
68
+ - `BoxScoreScoring` / `BoxScoreScoringV3` - Scoring breakdown
69
+ - `BoxScoreMisc` / `BoxScoreMiscV3` - Miscellaneous stats
70
+ - `BoxScoreUsage` / `BoxScoreUsageV3` - Usage rate stats
71
+ - `BoxScoreFourFactors` / `BoxScoreFourFactorsV3` - Four factors analysis
72
+ - `BoxScoreHustle` - Hustle stats (deflections, loose balls, etc.)
73
+ - `BoxScoreDefensiveV2` - Defensive statistics
74
+ - `BoxScorePlayerTrack` - Player tracking data (speed, distance, touches)
75
+ - `BoxScoreSummaryV2` / `BoxScoreSummaryV3` - Comprehensive game summaries
76
+ - `BoxScoreMatchupsV3` - Player matchup statistics
77
+ - `BoxScoreSimilarityScore` - Historical game similarity
78
+ - `HustleStatsBoxScore` - Detailed hustle box scores
79
+
80
+ #### League-Wide Endpoints
81
+ - `LeagueDashTeamStats` - League-wide team statistics
82
+ - `LeagueDashPlayerStats` - League-wide player statistics
83
+ - `LeagueDashLineups` - Lineup statistics across the league
84
+ - `LeagueDashPlayerBioStats` - Player biographical statistics
85
+ - `LeagueDashPlayerClutch` - Player clutch performance stats
86
+ - `LeagueDashTeamClutch` - Team clutch performance stats
87
+ - `LeagueDashPlayerPtShot` - Player tracking shot stats
88
+ - `LeagueDashTeamPtShot` - Team tracking shot stats
89
+ - `LeagueDashOppPtShot` - Opponent tracking shot stats
90
+ - `LeagueDashPlayerShotLocations` - Shot location breakdowns by player
91
+ - `LeagueDashTeamShotLocations` - Shot location breakdowns by team
92
+ - `LeagueDashPtDefend` - Player tracking defensive stats
93
+ - `LeagueDashPtTeamDefend` - Team tracking defensive stats
94
+ - `LeagueDashPtStats` - Player tracking general stats
95
+ - `LeagueLineupViz` - Lineup visualization data
96
+ - `LeaguePlayerOnDetails` - On-court impact details
97
+ - `LeagueSeasonMatchups` - Season matchup statistics
98
+ - `LeagueGameLog` - League-wide game logs
99
+ - `LeagueGameFinder` - Search for games by criteria
100
+ - `LeagueHustleStatsPlayer` / `LeagueHustleStatsTeam` - League hustle stats
101
+ - `LeagueStandings` - Detailed league standings
102
+
103
+ #### Standings & Leaders
104
+ - `Standings` - Conference and division standings
105
+ - `Leaders` - Current season statistical leaders
106
+ - `AllTimeLeaders` - All-time career statistical leaders
107
+ - `AssistLeaders` / `AssistTracker` - Assist-specific leaderboards
108
+ - `HomePageLeaders` / `LeadersTiles` - Home page leader data
109
+ - `ISTStandings` - In-Season Tournament standings
110
+ - `FranchiseLeaders` - Franchise all-time leaders
111
+ - `FranchiseHistory` - Franchise historical records
112
+ - `FranchisePlayers` - Players in franchise history
113
+
114
+ #### Game & Schedule
115
+ - `Games` / `Scoreboard` / `ScoreboardV3` - Today's games and scores
116
+ - `LiveScoreboard` - Real-time live game data
117
+ - `Schedule` / `ScheduleInternational` - Team and league schedules
118
+ - `GameRotation` - Player rotation data per game
119
+ - `PlayByPlay` / `PlayByPlayV3` - Play-by-play game data
120
+ - `LivePlayByPlay` - Real-time play-by-play
121
+ - `LiveBoxScore` - Real-time box scores
122
+ - `WinProbability` - In-game win probability
123
+
124
+ #### Shot Chart
125
+ - `ShotChart` - Individual player shot charts
126
+ - `ShotChartLeagueWide` - League-wide shot data
127
+ - `ShotChartLineupDetail` - Lineup-specific shot charts
128
+
129
+ #### Draft
130
+ - `DraftHistory` - Historical draft picks
131
+ - `DraftBoard` - Draft board data
132
+ - `DraftCombineStats` - Combine statistical results
133
+ - `DraftCombineSpotShooting` - Spot shooting drill results
134
+ - `DraftCombineDrillResults` - Agility and strength drills
135
+ - `DraftCombineNonStationaryShooting` - Non-stationary shooting
136
+ - `DraftCombinePlayerAnthro` - Anthropometric measurements
137
+
138
+ #### Video
139
+ - `VideoDetails` / `VideoDetailsAsset` - Video metadata and assets
140
+ - `VideoEvents` / `VideoEventsAsset` - Event-based video clips
141
+ - `VideoStatus` - Video availability status
142
+
143
+ #### Playoffs
144
+ - `CommonPlayoffSeries` - Playoff series information
145
+ - `PlayoffPicture` - Current playoff picture
146
+
147
+ #### Synergy & Advanced
148
+ - `SynergyPlayTypes` - Synergy play type statistics
149
+
150
+ #### Cumulative Stats
151
+ - `CumeStatsPlayer` / `CumeStatsPlayerGames` - Cumulative player stats
152
+ - `CumeStatsTeam` / `CumeStatsTeamGames` - Cumulative team stats
153
+
154
+ #### Other Features
155
+ - `DefenseHub` - Defensive statistics hub
156
+ - `FantasyWidget` - Fantasy basketball widget data
157
+ - `HomePageV2` - NBA.com home page data
158
+ - `MatchupsRollup` - Matchup summary data
159
+ - `InfographicFanDuelPlayer` - FanDuel player data
160
+ - `DunkScoreLeaders` - Dunk score leaderboards
161
+ - `Static` - Static reference data
162
+
163
+ #### Infrastructure
164
+ - `LiveConnection` - Real-time API connection for live data
165
+ - `ResponseParser` - Centralized response parsing
166
+ - Predicate methods for boolean-like API responses
167
+ - Support for multiple API response formats (v2/v3 endpoints)
168
+
169
+ [0.2.0]: https://github.com/sferik/nba-ruby/releases/tag/v0.2.0
data/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ AGENTS.md
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Erik Berlin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.