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,109 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "shot"
5
+ require_relative "league"
6
+ require_relative "response_parser"
7
+ require_relative "utils"
8
+
9
+ module NBA
10
+ # Provides methods to retrieve NBA shot chart lineup detail
11
+ module ShotChartLineupDetail
12
+ # Result set name for shot chart lineup detail
13
+ # @return [String] the result set name
14
+ DETAIL_SET = "ShotChartLineupDetail".freeze
15
+
16
+ # Result set name for league averages
17
+ # @return [String] the result set name
18
+ AVERAGE_SET = "ShotChartLineupLeagueAverage".freeze
19
+
20
+ # Retrieves shot chart lineup detail for a lineup group
21
+ #
22
+ # @api public
23
+ # @example
24
+ # shots = NBA::ShotChartLineupDetail.all(group_id: 12345, season: 2023)
25
+ # shots.each { |s| puts "#{s.player_name}: #{s.made? ? 'Made' : 'Missed'}" }
26
+ # @param group_id [Integer] the lineup group ID
27
+ # @param season [Integer] the season year (defaults to current season)
28
+ # @param season_type [String] the season type (Regular Season, Playoffs, etc.)
29
+ # @param context_measure [String] the context measure (FGA, FG3A, etc.)
30
+ # @param period [Integer] the period (0 for all periods)
31
+ # @param league [String, League] the league ID or League object
32
+ # @param client [Client] the API client to use
33
+ # @return [Collection] a collection of shots
34
+ def self.all(group_id:, season: Utils.current_season, season_type: "Regular Season",
35
+ context_measure: "FGA", period: 0, league: League::NBA, client: CLIENT)
36
+ league_id = Utils.extract_league_id(league)
37
+ opts = {group_id: group_id, season: season, season_type: season_type,
38
+ context_measure: context_measure, period: period, league_id: league_id}
39
+ ResponseParser.parse(client.get(build_path(opts)), result_set: DETAIL_SET) do |data|
40
+ build_shot(data)
41
+ end
42
+ end
43
+
44
+ # Builds the API request path
45
+ # @api private
46
+ # @return [String] the request path
47
+ def self.build_path(opts)
48
+ "shotchartlineupdetail?ContextMeasure=#{opts[:context_measure]}" \
49
+ "&GROUP_ID=#{opts[:group_id]}&LeagueID=#{opts[:league_id]}&Period=#{opts[:period]}" \
50
+ "&Season=#{Utils.format_season(opts[:season])}&SeasonType=#{opts[:season_type]}"
51
+ end
52
+ private_class_method :build_path
53
+
54
+ # Builds a Shot object from raw data
55
+ # @api private
56
+ # @param data [Hash] the row data
57
+ # @return [Shot] the shot object
58
+ def self.build_shot(data)
59
+ Shot.new(**shot_attributes(data))
60
+ end
61
+ private_class_method :build_shot
62
+
63
+ # Extracts shot attributes from data
64
+ # @api private
65
+ # @param data [Hash] the row data
66
+ # @return [Hash] shot attributes
67
+ def self.shot_attributes(data)
68
+ game_attributes(data).merge(player_attributes(data)).merge(shot_info_attributes(data))
69
+ end
70
+ private_class_method :shot_attributes
71
+
72
+ # Extracts game-related attributes
73
+ # @api private
74
+ # @param data [Hash] the row data
75
+ # @return [Hash] game attributes
76
+ def self.game_attributes(data)
77
+ {game_id: data["GAME_ID"], game_event_id: data["GAME_EVENT_ID"],
78
+ period: data["PERIOD"], minutes_remaining: data["MINUTES_REMAINING"],
79
+ seconds_remaining: data["SECONDS_REMAINING"]}
80
+ end
81
+ private_class_method :game_attributes
82
+
83
+ # Extracts player-related attributes
84
+ # @api private
85
+ # @param data [Hash] the row data
86
+ # @return [Hash] player attributes
87
+ def self.player_attributes(data)
88
+ {player_id: data["PLAYER_ID"], player_name: data["PLAYER_NAME"],
89
+ team_id: data["TEAM_ID"], team_name: data["TEAM_NAME"]}
90
+ end
91
+ private_class_method :player_attributes
92
+
93
+ # Extracts shot info attributes
94
+ # @api private
95
+ # @param data [Hash] the row data
96
+ # @return [Hash] shot info attributes
97
+ def self.shot_info_attributes(data)
98
+ {action_type: data["ACTION_TYPE"], shot_type: data["SHOT_TYPE"],
99
+ shot_zone_basic: data["SHOT_ZONE_BASIC"],
100
+ shot_zone_area: data["SHOT_ZONE_AREA"],
101
+ shot_zone_range: data["SHOT_ZONE_RANGE"],
102
+ shot_distance: data["SHOT_DISTANCE"],
103
+ loc_x: data["LOC_X"], loc_y: data["LOC_Y"],
104
+ shot_attempted_flag: data["SHOT_ATTEMPTED_FLAG"],
105
+ shot_made_flag: data["SHOT_MADE_FLAG"]}
106
+ end
107
+ private_class_method :shot_info_attributes
108
+ end
109
+ end
@@ -0,0 +1,174 @@
1
+ require "equalizer"
2
+ require "shale"
3
+ require_relative "players"
4
+
5
+ module NBA
6
+ # Represents a player's shot statistics
7
+ #
8
+ # @api public
9
+ class ShotStat < Shale::Mapper
10
+ include Equalizer.new(:player_id, :shot_type, :g)
11
+
12
+ # @!attribute [rw] player_id
13
+ # Returns the player ID
14
+ # @api public
15
+ # @example
16
+ # stat.player_id #=> 201939
17
+ # @return [Integer, nil] the player's ID
18
+ attribute :player_id, Shale::Type::Integer
19
+
20
+ # @!attribute [rw] player_name_last_first
21
+ # Returns the player name in "Last, First" format
22
+ # @api public
23
+ # @example
24
+ # stat.player_name_last_first #=> "Curry, Stephen"
25
+ # @return [String, nil] the player's name (last, first)
26
+ attribute :player_name_last_first, Shale::Type::String
27
+
28
+ # @!attribute [rw] sort_order
29
+ # Returns the sort order
30
+ # @api public
31
+ # @example
32
+ # stat.sort_order #=> 1
33
+ # @return [Integer, nil] the sort order
34
+ attribute :sort_order, Shale::Type::Integer
35
+
36
+ # @!attribute [rw] gp
37
+ # Returns games played
38
+ # @api public
39
+ # @example
40
+ # stat.gp #=> 74
41
+ # @return [Integer, nil] games played
42
+ attribute :gp, Shale::Type::Integer
43
+
44
+ # @!attribute [rw] g
45
+ # Returns number of games
46
+ # @api public
47
+ # @example
48
+ # stat.g #=> 74
49
+ # @return [Integer, nil] games
50
+ attribute :g, Shale::Type::Integer
51
+
52
+ # @!attribute [rw] shot_type
53
+ # Returns the shot type or category
54
+ # @api public
55
+ # @example
56
+ # stat.shot_type #=> "Catch and Shoot"
57
+ # @return [String, nil] the shot type or category
58
+ attribute :shot_type, Shale::Type::String
59
+
60
+ # @!attribute [rw] fga_frequency
61
+ # Returns field goal attempt frequency
62
+ # @api public
63
+ # @example
64
+ # stat.fga_frequency #=> 0.35
65
+ # @return [Float, nil] field goal attempt frequency
66
+ attribute :fga_frequency, Shale::Type::Float
67
+
68
+ # @!attribute [rw] fgm
69
+ # Returns field goals made
70
+ # @api public
71
+ # @example
72
+ # stat.fgm #=> 7.2
73
+ # @return [Float, nil] field goals made
74
+ attribute :fgm, Shale::Type::Float
75
+
76
+ # @!attribute [rw] fga
77
+ # Returns field goals attempted
78
+ # @api public
79
+ # @example
80
+ # stat.fga #=> 15.3
81
+ # @return [Float, nil] field goals attempted
82
+ attribute :fga, Shale::Type::Float
83
+
84
+ # @!attribute [rw] fg_pct
85
+ # Returns field goal percentage
86
+ # @api public
87
+ # @example
88
+ # stat.fg_pct #=> 0.472
89
+ # @return [Float, nil] field goal percentage
90
+ attribute :fg_pct, Shale::Type::Float
91
+
92
+ # @!attribute [rw] efg_pct
93
+ # Returns effective field goal percentage
94
+ # @api public
95
+ # @example
96
+ # stat.efg_pct #=> 0.561
97
+ # @return [Float, nil] effective field goal percentage
98
+ attribute :efg_pct, Shale::Type::Float
99
+
100
+ # @!attribute [rw] fg2a_frequency
101
+ # Returns 2-point field goal attempt frequency
102
+ # @api public
103
+ # @example
104
+ # stat.fg2a_frequency #=> 0.45
105
+ # @return [Float, nil] 2-point field goal attempt frequency
106
+ attribute :fg2a_frequency, Shale::Type::Float
107
+
108
+ # @!attribute [rw] fg2m
109
+ # Returns 2-point field goals made
110
+ # @api public
111
+ # @example
112
+ # stat.fg2m #=> 4.1
113
+ # @return [Float, nil] 2-point field goals made
114
+ attribute :fg2m, Shale::Type::Float
115
+
116
+ # @!attribute [rw] fg2a
117
+ # Returns 2-point field goals attempted
118
+ # @api public
119
+ # @example
120
+ # stat.fg2a #=> 7.8
121
+ # @return [Float, nil] 2-point field goals attempted
122
+ attribute :fg2a, Shale::Type::Float
123
+
124
+ # @!attribute [rw] fg2_pct
125
+ # Returns 2-point field goal percentage
126
+ # @api public
127
+ # @example
128
+ # stat.fg2_pct #=> 0.526
129
+ # @return [Float, nil] 2-point field goal percentage
130
+ attribute :fg2_pct, Shale::Type::Float
131
+
132
+ # @!attribute [rw] fg3a_frequency
133
+ # Returns 3-point field goal attempt frequency
134
+ # @api public
135
+ # @example
136
+ # stat.fg3a_frequency #=> 0.55
137
+ # @return [Float, nil] 3-point field goal attempt frequency
138
+ attribute :fg3a_frequency, Shale::Type::Float
139
+
140
+ # @!attribute [rw] fg3m
141
+ # Returns 3-point field goals made
142
+ # @api public
143
+ # @example
144
+ # stat.fg3m #=> 4.8
145
+ # @return [Float, nil] 3-point field goals made
146
+ attribute :fg3m, Shale::Type::Float
147
+
148
+ # @!attribute [rw] fg3a
149
+ # Returns 3-point field goals attempted
150
+ # @api public
151
+ # @example
152
+ # stat.fg3a #=> 11.2
153
+ # @return [Float, nil] 3-point field goals attempted
154
+ attribute :fg3a, Shale::Type::Float
155
+
156
+ # @!attribute [rw] fg3_pct
157
+ # Returns 3-point field goal percentage
158
+ # @api public
159
+ # @example
160
+ # stat.fg3_pct #=> 0.428
161
+ # @return [Float, nil] 3-point field goal percentage
162
+ attribute :fg3_pct, Shale::Type::Float
163
+
164
+ # Returns the player who took the shots
165
+ #
166
+ # @api public
167
+ # @example
168
+ # stat.player #=> #<NBA::Player id=201939 ...>
169
+ # @return [Player, nil] the player object
170
+ def player
171
+ Players.find(player_id)
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,129 @@
1
+ require "equalizer"
2
+ require "shale"
3
+ require_relative "teams"
4
+
5
+ module NBA
6
+ # Represents a team's standing in the league
7
+ class Standing < Shale::Mapper
8
+ include Equalizer.new(:team_id)
9
+
10
+ # @!attribute [rw] team_id
11
+ # Returns the team ID
12
+ # @api public
13
+ # @example
14
+ # standing.team_id #=> 1610612744
15
+ # @return [Integer] the team ID
16
+ attribute :team_id, Shale::Type::Integer
17
+
18
+ # @!attribute [rw] team_name
19
+ # Returns the team name
20
+ # @api public
21
+ # @example
22
+ # standing.team_name #=> "Golden State Warriors"
23
+ # @return [String] the team name
24
+ attribute :team_name, Shale::Type::String
25
+
26
+ # @!attribute [rw] conference
27
+ # Returns the conference
28
+ # @api public
29
+ # @example
30
+ # standing.conference #=> "West"
31
+ # @return [String] the conference
32
+ attribute :conference, Shale::Type::String
33
+
34
+ # @!attribute [rw] division
35
+ # Returns the division
36
+ # @api public
37
+ # @example
38
+ # standing.division #=> "Pacific"
39
+ # @return [String] the division
40
+ attribute :division, Shale::Type::String
41
+
42
+ # @!attribute [rw] wins
43
+ # Returns the number of wins
44
+ # @api public
45
+ # @example
46
+ # standing.wins #=> 45
47
+ # @return [Integer] the number of wins
48
+ attribute :wins, Shale::Type::Integer
49
+
50
+ # @!attribute [rw] losses
51
+ # Returns the number of losses
52
+ # @api public
53
+ # @example
54
+ # standing.losses #=> 30
55
+ # @return [Integer] the number of losses
56
+ attribute :losses, Shale::Type::Integer
57
+
58
+ # @!attribute [rw] win_pct
59
+ # Returns the win percentage
60
+ # @api public
61
+ # @example
62
+ # standing.win_pct #=> 0.600
63
+ # @return [Float] the win percentage
64
+ attribute :win_pct, Shale::Type::Float
65
+
66
+ # @!attribute [rw] conference_rank
67
+ # Returns the conference rank
68
+ # @api public
69
+ # @example
70
+ # standing.conference_rank #=> 5
71
+ # @return [Integer] the conference rank
72
+ attribute :conference_rank, Shale::Type::Integer
73
+
74
+ # @!attribute [rw] home_record
75
+ # Returns the home record
76
+ # @api public
77
+ # @example
78
+ # standing.home_record #=> "25-12"
79
+ # @return [String] the home record
80
+ attribute :home_record, Shale::Type::String
81
+
82
+ # @!attribute [rw] road_record
83
+ # Returns the road record
84
+ # @api public
85
+ # @example
86
+ # standing.road_record #=> "20-18"
87
+ # @return [String] the road record
88
+ attribute :road_record, Shale::Type::String
89
+
90
+ # @!attribute [rw] streak
91
+ # Returns the current streak
92
+ # @api public
93
+ # @example
94
+ # standing.streak #=> "W3"
95
+ # @return [String] the current streak
96
+ attribute :streak, Shale::Type::String
97
+
98
+ # Returns the team object for this standing
99
+ #
100
+ # @api public
101
+ # @example
102
+ # standing.team #=> #<NBA::Team>
103
+ # standing.team.city #=> "San Francisco"
104
+ # @return [Team, nil] the team object
105
+ def team
106
+ Teams.find(team_id)
107
+ end
108
+
109
+ json do
110
+ map "team_id", to: :team_id
111
+ map "teamId", to: :team_id
112
+ map "team_name", to: :team_name
113
+ map "teamName", to: :team_name
114
+ map "conference", to: :conference
115
+ map "division", to: :division
116
+ map "wins", to: :wins
117
+ map "losses", to: :losses
118
+ map "win_pct", to: :win_pct
119
+ map "winPct", to: :win_pct
120
+ map "conference_rank", to: :conference_rank
121
+ map "conferenceRank", to: :conference_rank
122
+ map "home_record", to: :home_record
123
+ map "homeRecord", to: :home_record
124
+ map "road_record", to: :road_record
125
+ map "roadRecord", to: :road_record
126
+ map "streak", to: :streak
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,75 @@
1
+ require_relative "client"
2
+ require_relative "response_parser"
3
+ require_relative "standing"
4
+ require_relative "utils"
5
+
6
+ module NBA
7
+ # Provides methods to retrieve NBA standings
8
+ module Standings
9
+ # Retrieves all team standings
10
+ #
11
+ # @api public
12
+ # @example
13
+ # standings = NBA::Standings.all
14
+ # standings.each { |s| puts "#{s.conference_rank}. #{s.team_name}: #{s.wins}-#{s.losses}" }
15
+ # @param season [Integer] the season year (defaults to current season)
16
+ # @param client [Client] the API client to use
17
+ # @return [Collection] a collection of standings
18
+ def self.all(season: Utils.current_season, client: CLIENT)
19
+ path = "leaguestandings?LeagueID=00&Season=#{Utils.format_season(season)}&SeasonType=Regular+Season"
20
+ ResponseParser.parse(client.get(path)) { |data| build_standing(data) }
21
+ end
22
+
23
+ # Retrieves standings for a specific conference
24
+ #
25
+ # @api public
26
+ # @example
27
+ # western = NBA::Standings.conference("West")
28
+ # @param conference_name [String] the conference name (East or West)
29
+ # @param season [Integer] the season year
30
+ # @param client [Client] the API client to use
31
+ # @return [Collection] a collection of standings for the conference
32
+ def self.conference(conference_name, season: Utils.current_season, client: CLIENT)
33
+ Collection.new(all(season: season, client: client).select { |s| s.conference.eql?(conference_name) })
34
+ end
35
+
36
+ # Builds a standing from API data
37
+ # @api private
38
+ # @return [Standing]
39
+ def self.build_standing(data)
40
+ Standing.new(**team_info(data), **record_info(data))
41
+ end
42
+ private_class_method :build_standing
43
+
44
+ # Extracts team information from data
45
+ # @api private
46
+ # @return [Hash]
47
+ def self.team_info(data)
48
+ {team_id: data["TeamID"], team_name: data["TeamName"],
49
+ conference: data["Conference"], division: data["Division"]}
50
+ end
51
+ private_class_method :team_info
52
+
53
+ # Extracts record information from data
54
+ # @api private
55
+ # @return [Hash]
56
+ def self.record_info(data)
57
+ {wins: data["WINS"], losses: data["LOSSES"], win_pct: data["WinPCT"],
58
+ conference_rank: parse_conference_rank(data["ConferenceRecord"], data["PlayoffRank"]),
59
+ home_record: data["HOME"], road_record: data["ROAD"], streak: data["strCurrentStreak"]}
60
+ end
61
+ private_class_method :record_info
62
+
63
+ # Parses conference rank from conference record or playoff rank
64
+ #
65
+ # @api private
66
+ # @param conference_record [String, Integer, nil] the conference record
67
+ # @param playoff_rank [Integer, nil] the playoff rank
68
+ # @return [Integer, nil] the conference rank
69
+ def self.parse_conference_rank(conference_record, playoff_rank)
70
+ wins = conference_record.to_s.split("-").first
71
+ (wins.nil? || wins.empty?) ? playoff_rank : wins.to_i
72
+ end
73
+ private_class_method :parse_conference_rank
74
+ end
75
+ end
data/lib/nba/static.rb ADDED
@@ -0,0 +1,107 @@
1
+ require_relative "data"
2
+ require_relative "team"
3
+
4
+ module NBA
5
+ # Provides static data lookup for teams without API calls
6
+ #
7
+ # @api public
8
+ module Static
9
+ # Retrieves all NBA teams
10
+ #
11
+ # @api public
12
+ # @example
13
+ # teams = NBA::Static.teams
14
+ # teams.size #=> 30
15
+ # @return [Array<Hash>] array of team hashes
16
+ def self.teams
17
+ Data::TEAMS
18
+ end
19
+
20
+ # Finds a team by ID
21
+ #
22
+ # @api public
23
+ # @example
24
+ # team = NBA::Static.find_team_by_id(1610612744)
25
+ # team[:full_name] #=> "Golden State Warriors"
26
+ # @param id [Integer] the team ID
27
+ # @return [Hash, nil] the team hash or nil if not found
28
+ def self.find_team_by_id(id)
29
+ Data::TEAMS.find { |t| t.fetch(:id).eql?(id) }
30
+ end
31
+
32
+ # Finds a team by abbreviation
33
+ #
34
+ # @api public
35
+ # @example
36
+ # team = NBA::Static.find_team_by_abbreviation("GSW")
37
+ # team[:full_name] #=> "Golden State Warriors"
38
+ # @param abbreviation [String] the team abbreviation
39
+ # @return [Hash, nil] the team hash or nil if not found
40
+ def self.find_team_by_abbreviation(abbreviation)
41
+ Data::TEAMS.find { |t| t.fetch(:abbreviation).casecmp?(abbreviation) }
42
+ end
43
+
44
+ # Finds teams by city name
45
+ #
46
+ # @api public
47
+ # @example
48
+ # teams = NBA::Static.find_teams_by_city("Los Angeles")
49
+ # teams.size #=> 2
50
+ # @param city [String] the city name (case-insensitive, partial match)
51
+ # @return [Array<Hash>] array of matching team hashes
52
+ def self.find_teams_by_city(city)
53
+ pattern = Regexp.new(Regexp.escape(city), Regexp::IGNORECASE)
54
+ Data::TEAMS.select { |t| pattern.match?(t.fetch(:city)) }
55
+ end
56
+
57
+ # Finds teams by state name
58
+ #
59
+ # @api public
60
+ # @example
61
+ # teams = NBA::Static.find_teams_by_state("California")
62
+ # teams.size #=> 4
63
+ # @param state [String] the state name (case-insensitive, partial match)
64
+ # @return [Array<Hash>] array of matching team hashes
65
+ def self.find_teams_by_state(state)
66
+ pattern = Regexp.new(Regexp.escape(state), Regexp::IGNORECASE)
67
+ Data::TEAMS.select { |t| pattern.match?(t.fetch(:state)) }
68
+ end
69
+
70
+ # Finds teams by nickname
71
+ #
72
+ # @api public
73
+ # @example
74
+ # team = NBA::Static.find_team_by_nickname("Warriors")
75
+ # team[:city] #=> "San Francisco"
76
+ # @param nickname [String] the team nickname (case-insensitive)
77
+ # @return [Hash, nil] the team hash or nil if not found
78
+ def self.find_team_by_nickname(nickname)
79
+ Data::TEAMS.find { |t| t.fetch(:nickname).casecmp?(nickname) }
80
+ end
81
+
82
+ # Finds teams by full name
83
+ #
84
+ # @api public
85
+ # @example
86
+ # teams = NBA::Static.find_teams_by_full_name("Warriors")
87
+ # teams.first[:city] #=> "San Francisco"
88
+ # @param name [String] the name to search (case-insensitive, partial match)
89
+ # @return [Array<Hash>] array of matching team hashes
90
+ def self.find_teams_by_full_name(name)
91
+ pattern = Regexp.new(Regexp.escape(name), Regexp::IGNORECASE)
92
+ Data::TEAMS.select { |t| pattern.match?(t.fetch(:full_name)) }
93
+ end
94
+
95
+ # Finds teams by year founded
96
+ #
97
+ # @api public
98
+ # @example
99
+ # teams = NBA::Static.find_teams_by_year_founded(1946)
100
+ # teams.size #=> 4
101
+ # @param year [Integer] the founding year
102
+ # @return [Array<Hash>] array of matching team hashes
103
+ def self.find_teams_by_year_founded(year)
104
+ Data::TEAMS.select { |t| t.fetch(:year_founded).eql?(year) }
105
+ end
106
+ end
107
+ end