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,162 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "franchise_leader"
4
+
5
+ module NBA
6
+ # Provides methods to retrieve franchise leaders
7
+ module FranchiseLeaders
8
+ # Result set name for franchise leaders
9
+ # @return [String] the result set name
10
+ RESULTS = "FranchiseLeaders".freeze
11
+
12
+ # Retrieves franchise leaders for a team
13
+ #
14
+ # @api public
15
+ # @example
16
+ # leader = NBA::FranchiseLeaders.find(team: NBA::Team::GSW)
17
+ # puts "Points: #{leader.pts_player_name} (#{leader.pts})"
18
+ # @param team [Integer, Team] the team ID or Team object
19
+ # @param league [String, League] the league ID or League object (default NBA)
20
+ # @param client [Client] the API client to use
21
+ # @return [FranchiseLeader, nil] the franchise leader
22
+ def self.find(team:, league: League::NBA, client: CLIENT)
23
+ team_id = extract_team_id(team)
24
+ league_id = Utils.extract_league_id(league)
25
+ path = "franchiseleaders?TeamID=#{team_id}&LeagueID=#{league_id}"
26
+ response = client.get(path)
27
+ parse_response(response)
28
+ end
29
+
30
+ # Parses the API response
31
+ #
32
+ # @api private
33
+ # @param response [String] the JSON response body
34
+ # @return [FranchiseLeader, nil] the franchise leader
35
+ def self.parse_response(response)
36
+ return unless response
37
+
38
+ data = JSON.parse(response)
39
+ result_set = find_result_set(data, RESULTS)
40
+ return unless result_set
41
+
42
+ headers = result_set["headers"]
43
+ row = result_set.dig("rowSet", 0)
44
+ return unless headers && row
45
+
46
+ build_franchise_leader(headers, row)
47
+ end
48
+ private_class_method :parse_response
49
+
50
+ # Finds a result set by name
51
+ #
52
+ # @api private
53
+ # @param data [Hash] the parsed JSON data
54
+ # @param name [String] the result set name
55
+ # @return [Hash, nil] the result set
56
+ def self.find_result_set(data, name)
57
+ result_sets = data["resultSets"]
58
+ return unless result_sets
59
+
60
+ result_sets.find { |rs| rs["name"].eql?(name) }
61
+ end
62
+ private_class_method :find_result_set
63
+
64
+ # Builds a franchise leader from a row
65
+ #
66
+ # @api private
67
+ # @param headers [Array<String>] the column headers
68
+ # @param row [Array] the row data
69
+ # @return [FranchiseLeader] the franchise leader object
70
+ def self.build_franchise_leader(headers, row)
71
+ data = headers.zip(row).to_h
72
+ FranchiseLeader.new(**franchise_leader_attributes(data))
73
+ end
74
+ private_class_method :build_franchise_leader
75
+
76
+ # Extracts franchise leader attributes from row data
77
+ #
78
+ # @api private
79
+ # @param data [Hash] the franchise leader row data
80
+ # @return [Hash] the franchise leader attributes
81
+ def self.franchise_leader_attributes(data)
82
+ team_attributes(data).merge(points_attributes(data), assists_attributes(data),
83
+ rebounds_attributes(data), blocks_attributes(data), steals_attributes(data))
84
+ end
85
+ private_class_method :franchise_leader_attributes
86
+
87
+ # Extracts team attributes
88
+ #
89
+ # @api private
90
+ # @param data [Hash] the franchise leader data
91
+ # @return [Hash] the team attributes
92
+ def self.team_attributes(data)
93
+ {team_id: data.fetch("TEAM_ID")}
94
+ end
95
+ private_class_method :team_attributes
96
+
97
+ # Extracts points leader attributes
98
+ #
99
+ # @api private
100
+ # @param data [Hash] the franchise leader data
101
+ # @return [Hash] the points attributes
102
+ def self.points_attributes(data)
103
+ {pts_person_id: data.fetch("PTS_PERSON_ID"), pts_player_name: data.fetch("PTS_PLAYER"),
104
+ pts: data.fetch("PTS")}
105
+ end
106
+ private_class_method :points_attributes
107
+
108
+ # Extracts assists leader attributes
109
+ #
110
+ # @api private
111
+ # @param data [Hash] the franchise leader data
112
+ # @return [Hash] the assists attributes
113
+ def self.assists_attributes(data)
114
+ {ast_person_id: data.fetch("AST_PERSON_ID"), ast_player_name: data.fetch("AST_PLAYER"),
115
+ ast: data.fetch("AST")}
116
+ end
117
+ private_class_method :assists_attributes
118
+
119
+ # Extracts rebounds leader attributes
120
+ #
121
+ # @api private
122
+ # @param data [Hash] the franchise leader data
123
+ # @return [Hash] the rebounds attributes
124
+ def self.rebounds_attributes(data)
125
+ {reb_person_id: data.fetch("REB_PERSON_ID"), reb_player_name: data.fetch("REB_PLAYER"),
126
+ reb: data.fetch("REB")}
127
+ end
128
+ private_class_method :rebounds_attributes
129
+
130
+ # Extracts blocks leader attributes
131
+ #
132
+ # @api private
133
+ # @param data [Hash] the franchise leader data
134
+ # @return [Hash] the blocks attributes
135
+ def self.blocks_attributes(data)
136
+ {blk_person_id: data.fetch("BLK_PERSON_ID"), blk_player_name: data.fetch("BLK_PLAYER"),
137
+ blk: data.fetch("BLK")}
138
+ end
139
+ private_class_method :blocks_attributes
140
+
141
+ # Extracts steals leader attributes
142
+ #
143
+ # @api private
144
+ # @param data [Hash] the franchise leader data
145
+ # @return [Hash] the steals attributes
146
+ def self.steals_attributes(data)
147
+ {stl_person_id: data.fetch("STL_PERSON_ID"), stl_player_name: data.fetch("STL_PLAYER"),
148
+ stl: data.fetch("STL")}
149
+ end
150
+ private_class_method :steals_attributes
151
+
152
+ # Extracts team ID from team object or integer
153
+ #
154
+ # @api private
155
+ # @param team [Integer, Team] the team ID or Team object
156
+ # @return [Integer] the team ID
157
+ def self.extract_team_id(team)
158
+ team.instance_of?(Team) ? team.id : team
159
+ end
160
+ private_class_method :extract_team_id
161
+ end
162
+ end
@@ -0,0 +1,224 @@
1
+ module NBA
2
+ # Represents a player's franchise statistics
3
+ class FranchisePlayer < Shale::Mapper
4
+ include Equalizer.new(:person_id)
5
+
6
+ # @!attribute [rw] league_id
7
+ # Returns the league ID
8
+ # @api public
9
+ # @example
10
+ # player.league_id #=> "00"
11
+ # @return [String] the league ID
12
+ attribute :league_id, Shale::Type::String
13
+
14
+ # @!attribute [rw] team_id
15
+ # Returns the team ID
16
+ # @api public
17
+ # @example
18
+ # player.team_id #=> 1610612744
19
+ # @return [Integer] the team ID
20
+ attribute :team_id, Shale::Type::Integer
21
+
22
+ # @!attribute [rw] team
23
+ # Returns the team name
24
+ # @api public
25
+ # @example
26
+ # player.team #=> "Golden State Warriors"
27
+ # @return [String] the team name
28
+ attribute :team, Shale::Type::String
29
+
30
+ # @!attribute [rw] person_id
31
+ # Returns the player ID
32
+ # @api public
33
+ # @example
34
+ # player.person_id #=> 201939
35
+ # @return [Integer] the player ID
36
+ attribute :person_id, Shale::Type::Integer
37
+
38
+ # @!attribute [rw] player
39
+ # Returns the player name
40
+ # @api public
41
+ # @example
42
+ # player.player #=> "Stephen Curry"
43
+ # @return [String] the player name
44
+ attribute :player, Shale::Type::String
45
+
46
+ # @!attribute [rw] season_type
47
+ # Returns the season type
48
+ # @api public
49
+ # @example
50
+ # player.season_type #=> "Regular Season"
51
+ # @return [String] the season type
52
+ attribute :season_type, Shale::Type::String
53
+
54
+ # @!attribute [rw] active_with_team
55
+ # Returns whether the player is active with the team
56
+ # @api public
57
+ # @example
58
+ # player.active_with_team #=> "Y"
59
+ # @return [String] the active status
60
+ attribute :active_with_team, Shale::Type::String
61
+
62
+ # @!attribute [rw] gp
63
+ # Returns the games played
64
+ # @api public
65
+ # @example
66
+ # player.gp #=> 745
67
+ # @return [Integer] the games played
68
+ attribute :gp, Shale::Type::Integer
69
+
70
+ # @!attribute [rw] fgm
71
+ # Returns the field goals made
72
+ # @api public
73
+ # @example
74
+ # player.fgm #=> 9.2
75
+ # @return [Float] the field goals made
76
+ attribute :fgm, Shale::Type::Float
77
+
78
+ # @!attribute [rw] fga
79
+ # Returns the field goals attempted
80
+ # @api public
81
+ # @example
82
+ # player.fga #=> 19.3
83
+ # @return [Float] the field goals attempted
84
+ attribute :fga, Shale::Type::Float
85
+
86
+ # @!attribute [rw] fg_pct
87
+ # Returns the field goal percentage
88
+ # @api public
89
+ # @example
90
+ # player.fg_pct #=> 0.476
91
+ # @return [Float] the field goal percentage
92
+ attribute :fg_pct, Shale::Type::Float
93
+
94
+ # @!attribute [rw] fg3m
95
+ # Returns the three-point field goals made
96
+ # @api public
97
+ # @example
98
+ # player.fg3m #=> 4.5
99
+ # @return [Float] the three-point field goals made
100
+ attribute :fg3m, Shale::Type::Float
101
+
102
+ # @!attribute [rw] fg3a
103
+ # Returns the three-point field goals attempted
104
+ # @api public
105
+ # @example
106
+ # player.fg3a #=> 11.2
107
+ # @return [Float] the three-point field goals attempted
108
+ attribute :fg3a, Shale::Type::Float
109
+
110
+ # @!attribute [rw] fg3_pct
111
+ # Returns the three-point field goal percentage
112
+ # @api public
113
+ # @example
114
+ # player.fg3_pct #=> 0.426
115
+ # @return [Float] the three-point field goal percentage
116
+ attribute :fg3_pct, Shale::Type::Float
117
+
118
+ # @!attribute [rw] ftm
119
+ # Returns the free throws made
120
+ # @api public
121
+ # @example
122
+ # player.ftm #=> 4.8
123
+ # @return [Float] the free throws made
124
+ attribute :ftm, Shale::Type::Float
125
+
126
+ # @!attribute [rw] fta
127
+ # Returns the free throws attempted
128
+ # @api public
129
+ # @example
130
+ # player.fta #=> 5.3
131
+ # @return [Float] the free throws attempted
132
+ attribute :fta, Shale::Type::Float
133
+
134
+ # @!attribute [rw] ft_pct
135
+ # Returns the free throw percentage
136
+ # @api public
137
+ # @example
138
+ # player.ft_pct #=> 0.908
139
+ # @return [Float] the free throw percentage
140
+ attribute :ft_pct, Shale::Type::Float
141
+
142
+ # @!attribute [rw] oreb
143
+ # Returns the offensive rebounds
144
+ # @api public
145
+ # @example
146
+ # player.oreb #=> 0.5
147
+ # @return [Float] the offensive rebounds
148
+ attribute :oreb, Shale::Type::Float
149
+
150
+ # @!attribute [rw] dreb
151
+ # Returns the defensive rebounds
152
+ # @api public
153
+ # @example
154
+ # player.dreb #=> 4.5
155
+ # @return [Float] the defensive rebounds
156
+ attribute :dreb, Shale::Type::Float
157
+
158
+ # @!attribute [rw] reb
159
+ # Returns the total rebounds
160
+ # @api public
161
+ # @example
162
+ # player.reb #=> 5.0
163
+ # @return [Float] the total rebounds
164
+ attribute :reb, Shale::Type::Float
165
+
166
+ # @!attribute [rw] ast
167
+ # Returns the assists
168
+ # @api public
169
+ # @example
170
+ # player.ast #=> 6.5
171
+ # @return [Float] the assists
172
+ attribute :ast, Shale::Type::Float
173
+
174
+ # @!attribute [rw] pf
175
+ # Returns the personal fouls
176
+ # @api public
177
+ # @example
178
+ # player.pf #=> 2.1
179
+ # @return [Float] the personal fouls
180
+ attribute :pf, Shale::Type::Float
181
+
182
+ # @!attribute [rw] stl
183
+ # Returns the steals
184
+ # @api public
185
+ # @example
186
+ # player.stl #=> 1.6
187
+ # @return [Float] the steals
188
+ attribute :stl, Shale::Type::Float
189
+
190
+ # @!attribute [rw] tov
191
+ # Returns the turnovers
192
+ # @api public
193
+ # @example
194
+ # player.tov #=> 3.1
195
+ # @return [Float] the turnovers
196
+ attribute :tov, Shale::Type::Float
197
+
198
+ # @!attribute [rw] blk
199
+ # Returns the blocks
200
+ # @api public
201
+ # @example
202
+ # player.blk #=> 0.2
203
+ # @return [Float] the blocks
204
+ attribute :blk, Shale::Type::Float
205
+
206
+ # @!attribute [rw] pts
207
+ # Returns the points
208
+ # @api public
209
+ # @example
210
+ # player.pts #=> 24.8
211
+ # @return [Float] the points
212
+ attribute :pts, Shale::Type::Float
213
+
214
+ # Returns the player information
215
+ #
216
+ # @api public
217
+ # @example
218
+ # franchise_player.player_info #=> #<NBA::Player>
219
+ # @return [Player, nil] the player object
220
+ def player_info
221
+ Players.find(person_id)
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,147 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "franchise_player"
5
+
6
+ module NBA
7
+ # Provides methods to retrieve franchise player statistics
8
+ module FranchisePlayers
9
+ # Result set name for franchise players
10
+ # @return [String] the result set name
11
+ RESULTS = "FranchisePlayers".freeze
12
+
13
+ # Per mode constant for per game stats
14
+ # @return [String] the per game mode
15
+ PER_GAME = "PerGame".freeze
16
+
17
+ # Per mode constant for totals stats
18
+ # @return [String] the totals mode
19
+ TOTALS = "Totals".freeze
20
+
21
+ # Retrieves all franchise player statistics
22
+ #
23
+ # @api public
24
+ # @example
25
+ # players = NBA::FranchisePlayers.all(team: 1610612744)
26
+ # players.each { |p| puts "#{p.player}: #{p.pts} PPG" }
27
+ # @param team [Integer, String, Team] the team ID or Team object
28
+ # @param season_type [String] the season type (default "Regular Season")
29
+ # @param per_mode [String] the per mode (default PER_GAME)
30
+ # @param league [String, League] the league ID or League object (default NBA)
31
+ # @param client [Client] the API client to use
32
+ # @return [Collection] a collection of franchise players
33
+ def self.all(team:, season_type: "Regular Season", per_mode: PER_GAME, league: League::NBA, client: CLIENT)
34
+ team_id = Utils.extract_id(team)
35
+ return Collection.new unless team_id
36
+
37
+ league_id = Utils.extract_league_id(league)
38
+ path = "franchiseplayers?TeamID=#{team_id}&SeasonType=#{season_type}&PerMode=#{per_mode}&LeagueID=#{league_id}"
39
+ response = client.get(path)
40
+ parse_response(response)
41
+ end
42
+
43
+ # Parses the API response
44
+ #
45
+ # @api private
46
+ # @param response [String] the JSON response body
47
+ # @return [Collection] a collection of franchise players
48
+ def self.parse_response(response)
49
+ return Collection.new unless response
50
+
51
+ data = JSON.parse(response)
52
+ result_set = find_result_set(data, RESULTS)
53
+ return Collection.new unless result_set
54
+
55
+ headers = result_set["headers"]
56
+ rows = result_set["rowSet"]
57
+ return Collection.new unless headers && rows
58
+
59
+ players = rows.map { |row| build_player(headers, row) }
60
+ Collection.new(players)
61
+ end
62
+ private_class_method :parse_response
63
+
64
+ # Finds a result set by name
65
+ #
66
+ # @api private
67
+ # @param data [Hash] the parsed JSON data
68
+ # @param name [String] the result set name
69
+ # @return [Hash, nil] the result set
70
+ def self.find_result_set(data, name)
71
+ result_sets = data["resultSets"]
72
+ return unless result_sets
73
+
74
+ result_sets.find { |rs| rs["name"].eql?(name) }
75
+ end
76
+ private_class_method :find_result_set
77
+
78
+ # Builds a franchise player from a row
79
+ #
80
+ # @api private
81
+ # @param headers [Array<String>] the column headers
82
+ # @param row [Array] the row data
83
+ # @return [FranchisePlayer] the franchise player object
84
+ def self.build_player(headers, row)
85
+ data = headers.zip(row).to_h
86
+ FranchisePlayer.new(**player_attributes(data))
87
+ end
88
+ private_class_method :build_player
89
+
90
+ # Extracts player attributes from row data
91
+ #
92
+ # @api private
93
+ # @param data [Hash] the player row data
94
+ # @return [Hash] the player attributes
95
+ def self.player_attributes(data)
96
+ identity_attributes(data).merge(stats_attributes(data), shooting_attributes(data), rebound_attributes(data))
97
+ end
98
+ private_class_method :player_attributes
99
+
100
+ # Extracts identity attributes
101
+ #
102
+ # @api private
103
+ # @param data [Hash] the player data
104
+ # @return [Hash] the identity attributes
105
+ def self.identity_attributes(data)
106
+ {league_id: data["LEAGUE_ID"], team_id: data["TEAM_ID"],
107
+ team: data["TEAM"], person_id: data["PERSON_ID"],
108
+ player: data["PLAYER"], season_type: data["SEASON_TYPE"],
109
+ active_with_team: data["ACTIVE_WITH_TEAM"]}
110
+ end
111
+ private_class_method :identity_attributes
112
+
113
+ # Extracts basic stats attributes
114
+ #
115
+ # @api private
116
+ # @param data [Hash] the player data
117
+ # @return [Hash] the stats attributes
118
+ def self.stats_attributes(data)
119
+ {gp: data["GP"], ast: data["AST"], pf: data["PF"],
120
+ stl: data["STL"], tov: data["TOV"], blk: data["BLK"],
121
+ pts: data["PTS"]}
122
+ end
123
+ private_class_method :stats_attributes
124
+
125
+ # Extracts shooting attributes
126
+ #
127
+ # @api private
128
+ # @param data [Hash] the player data
129
+ # @return [Hash] the shooting attributes
130
+ def self.shooting_attributes(data)
131
+ {fgm: data["FGM"], fga: data["FGA"], fg_pct: data["FG_PCT"],
132
+ fg3m: data["FG3M"], fg3a: data["FG3A"], fg3_pct: data["FG3_PCT"],
133
+ ftm: data["FTM"], fta: data["FTA"], ft_pct: data["FT_PCT"]}
134
+ end
135
+ private_class_method :shooting_attributes
136
+
137
+ # Extracts rebound attributes
138
+ #
139
+ # @api private
140
+ # @param data [Hash] the player data
141
+ # @return [Hash] the rebound attributes
142
+ def self.rebound_attributes(data)
143
+ {oreb: data["OREB"], dreb: data["DREB"], reb: data["REB"]}
144
+ end
145
+ private_class_method :rebound_attributes
146
+ end
147
+ end
data/lib/nba/game.rb CHANGED
@@ -1,76 +1,92 @@
1
- module NBA
2
- class Game
3
- attr_reader :home_team, :home_score, :away_team, :away_score, :status
1
+ require "equalizer"
2
+ require "shale"
3
+ require_relative "team"
4
4
 
5
- # Returns an array of Team objects
6
- #
7
- # @example
8
- # NBA::Game.all '20140102'
9
- # >> Final/OT - Cavaliers 87 : 81 Magic
10
- # >> Final - Heat 114 : 123 Warriors
11
- # >> Final - Bulls 94 : 82 Celtics
12
- # >> Final - Thunder 93 : 95 Nets
13
- # >> Final - Spurs 101 : 105 Knicks
14
- # >> Final - Suns 91 : 99 Grizzlies
15
- # >> Final - Jazz 96 : 87 Bucks
16
- # >> Final - Trail Blazers 134 : 104 Bobcats
17
- # >> Final - Kings 104 : 113 76ers
18
- def self.all(date = (Time.now.utc - 5 * 60 * 60).strftime("%Y%m%d"))
19
- results = scoreboard(date)
5
+ module NBA
6
+ # Represents an NBA game
7
+ class Game < Shale::Mapper
8
+ include Equalizer.new(:id)
20
9
 
21
- if results == 'fail'
22
- puts "Fail to fetch game scoreboard/schedule!"
23
- else
24
- puts scoreboard(date).join("\n")
25
- end
26
- end
10
+ # @!attribute [rw] id
11
+ # Returns the unique identifier for the game
12
+ # @api public
13
+ # @example
14
+ # game.id #=> "0022400001"
15
+ # @return [String] the unique identifier for the game
16
+ attribute :id, Shale::Type::String
27
17
 
28
- def self.scoreboard(date = (Time.now.utc - 5 * 60 * 60).strftime("%Y%m%d"))
29
- begin
30
- format_games(results_to_game(results_from_espn(date)))
31
- rescue Faraday::Error::ConnectionFailed, Faraday::Error::TimeoutError, Errno::EHOSTUNREACH
32
- "fail"
33
- end
34
- end
18
+ # @!attribute [rw] date
19
+ # Returns the date of the game
20
+ # @api public
21
+ # @example
22
+ # game.date #=> "2024-10-22"
23
+ # @return [String] the date of the game
24
+ attribute :date, Shale::Type::String
35
25
 
36
- def pretty_format(options = {})
37
- self.status.center(options[:status_length].to_i + 1) + " - " + \
38
- self.home_team.center(options[:home_length].to_i + 1) + " " + \
39
- self.home_score.center(options[:home_score].to_i + 1) + " : " + \
40
- self.away_score.center(options[:away_score].to_i + 1) + " " + \
41
- self.away_team.center(options[:away_length].to_i + 1)
42
- end
26
+ # @!attribute [rw] status
27
+ # Returns the game status
28
+ # @api public
29
+ # @example
30
+ # game.status #=> "Final"
31
+ # @return [String] the game status
32
+ attribute :status, Shale::Type::String
43
33
 
44
- private
34
+ # @!attribute [rw] home_team
35
+ # Returns the home team
36
+ # @api public
37
+ # @example
38
+ # game.home_team #=> #<NBA::Team>
39
+ # @return [Team] the home team
40
+ attribute :home_team, Team
45
41
 
46
- def initialize(attributes = {})
47
- attributes.each do |key, value|
48
- instance_variable_set("@#{key}", value) if self.respond_to?(key)
49
- end
50
- end
42
+ # @!attribute [rw] away_team
43
+ # Returns the away team
44
+ # @api public
45
+ # @example
46
+ # game.away_team #=> #<NBA::Team>
47
+ # @return [Team] the away team
48
+ attribute :away_team, Team
51
49
 
52
- def self.length_options_of(games)
53
- {
54
- :status_length => games.map(&:status).map(&:length).max,
55
- :home_length => games.map(&:home_team).map(&:length).max,
56
- :home_score => games.map(&:home_score).map(&:length).max,
57
- :away_length => games.map(&:away_team).map(&:length).max,
58
- :away_score => games.map(&:away_score).map(&:length).max
59
- }
60
- end
50
+ # @!attribute [rw] home_score
51
+ # Returns the home team score
52
+ # @api public
53
+ # @example
54
+ # game.home_score #=> 112
55
+ # @return [Integer] the home team score
56
+ attribute :home_score, Shale::Type::Integer
61
57
 
62
- def self.format_games(games)
63
- length_options = length_options_of(games)
64
- games.map { |game| game.pretty_format(length_options) }
65
- end
58
+ # @!attribute [rw] away_score
59
+ # Returns the away team score
60
+ # @api public
61
+ # @example
62
+ # game.away_score #=> 108
63
+ # @return [Integer] the away team score
64
+ attribute :away_score, Shale::Type::Integer
66
65
 
67
- def self.results_to_game(results)
68
- results.map { |result| new result }
69
- end
66
+ # @!attribute [rw] arena
67
+ # Returns the arena where the game is played
68
+ # @api public
69
+ # @example
70
+ # game.arena #=> "Chase Center"
71
+ # @return [String] the arena name
72
+ attribute :arena, Shale::Type::String
70
73
 
71
- def self.results_from_espn(date)
72
- options = {:date => date}
73
- Request.get_games('/nba/scoreboard', options)
74
- end
74
+ json do
75
+ map "id", to: :id
76
+ map "gameId", to: :id
77
+ map "date", to: :date
78
+ map "gameDate", to: :date
79
+ map "status", to: :status
80
+ map "gameStatus", to: :status
81
+ map "home_team", to: :home_team
82
+ map "homeTeam", to: :home_team
83
+ map "away_team", to: :away_team
84
+ map "awayTeam", to: :away_team
85
+ map "home_score", to: :home_score
86
+ map "homeScore", to: :home_score
87
+ map "away_score", to: :away_score
88
+ map "awayScore", to: :away_score
89
+ map "arena", to: :arena
90
+ end
75
91
  end
76
92
  end