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,285 @@
1
+ require "equalizer"
2
+ require "shale"
3
+
4
+ module NBA
5
+ # Represents game summary information
6
+ class BoxScoreSummary < Shale::Mapper
7
+ include Equalizer.new(:game_id)
8
+
9
+ # @!attribute [rw] game_id
10
+ # Returns the game ID
11
+ # @api public
12
+ # @example
13
+ # summary.game_id #=> "0022400001"
14
+ # @return [String] the game ID
15
+ attribute :game_id, Shale::Type::String
16
+
17
+ # @!attribute [rw] game_date
18
+ # Returns the game date
19
+ # @api public
20
+ # @example
21
+ # summary.game_date #=> "2024-10-22"
22
+ # @return [String] the game date
23
+ attribute :game_date, Shale::Type::String
24
+
25
+ # @!attribute [rw] game_status_id
26
+ # Returns the game status ID
27
+ # @api public
28
+ # @example
29
+ # summary.game_status_id #=> 3
30
+ # @return [Integer] the status ID
31
+ attribute :game_status_id, Shale::Type::Integer
32
+
33
+ # @!attribute [rw] game_status_text
34
+ # Returns the game status text
35
+ # @api public
36
+ # @example
37
+ # summary.game_status_text #=> "Final"
38
+ # @return [String] the status text
39
+ attribute :game_status_text, Shale::Type::String
40
+
41
+ # @!attribute [rw] home_team_id
42
+ # Returns the home team ID
43
+ # @api public
44
+ # @example
45
+ # summary.home_team_id #=> 1610612744
46
+ # @return [Integer] the home team ID
47
+ attribute :home_team_id, Shale::Type::Integer
48
+
49
+ # @!attribute [rw] visitor_team_id
50
+ # Returns the visitor team ID
51
+ # @api public
52
+ # @example
53
+ # summary.visitor_team_id #=> 1610612747
54
+ # @return [Integer] the visitor team ID
55
+ attribute :visitor_team_id, Shale::Type::Integer
56
+
57
+ # @!attribute [rw] season
58
+ # Returns the season
59
+ # @api public
60
+ # @example
61
+ # summary.season #=> "2024-25"
62
+ # @return [String] the season
63
+ attribute :season, Shale::Type::String
64
+
65
+ # @!attribute [rw] live_period
66
+ # Returns the current period if live
67
+ # @api public
68
+ # @example
69
+ # summary.live_period #=> 4
70
+ # @return [Integer] the live period
71
+ attribute :live_period, Shale::Type::Integer
72
+
73
+ # @!attribute [rw] live_pc_time
74
+ # Returns the time on the clock if live
75
+ # @api public
76
+ # @example
77
+ # summary.live_pc_time #=> "0:00"
78
+ # @return [String] the live clock time
79
+ attribute :live_pc_time, Shale::Type::String
80
+
81
+ # @!attribute [rw] attendance
82
+ # Returns the attendance
83
+ # @api public
84
+ # @example
85
+ # summary.attendance #=> 18064
86
+ # @return [Integer] the attendance
87
+ attribute :attendance, Shale::Type::Integer
88
+
89
+ # @!attribute [rw] game_time
90
+ # Returns the game duration
91
+ # @api public
92
+ # @example
93
+ # summary.game_time #=> "2:18"
94
+ # @return [String] the game time
95
+ attribute :game_time, Shale::Type::String
96
+
97
+ # @!attribute [rw] arena
98
+ # Returns the arena name
99
+ # @api public
100
+ # @example
101
+ # summary.arena #=> "Chase Center"
102
+ # @return [String] the arena
103
+ attribute :arena, Shale::Type::String
104
+
105
+ # @!attribute [rw] lead_changes
106
+ # Returns the number of lead changes
107
+ # @api public
108
+ # @example
109
+ # summary.lead_changes #=> 12
110
+ # @return [Integer] lead changes
111
+ attribute :lead_changes, Shale::Type::Integer
112
+
113
+ # @!attribute [rw] times_tied
114
+ # Returns the number of times tied
115
+ # @api public
116
+ # @example
117
+ # summary.times_tied #=> 8
118
+ # @return [Integer] times tied
119
+ attribute :times_tied, Shale::Type::Integer
120
+
121
+ # @!attribute [rw] officials
122
+ # Returns the game officials
123
+ # @api public
124
+ # @example
125
+ # summary.officials #=> ["Scott Foster", "Tony Brothers", "Marc Davis"]
126
+ # @return [Array<String>] the officials
127
+ attribute :officials, Shale::Type::String, collection: true
128
+
129
+ # @!attribute [rw] home_pts_q1
130
+ # Returns home team Q1 points
131
+ # @api public
132
+ # @example
133
+ # summary.home_pts_q1 #=> 28
134
+ # @return [Integer] Q1 points
135
+ attribute :home_pts_q1, Shale::Type::Integer
136
+
137
+ # @!attribute [rw] home_pts_q2
138
+ # Returns home team Q2 points
139
+ # @api public
140
+ # @example
141
+ # summary.home_pts_q2 #=> 32
142
+ # @return [Integer] Q2 points
143
+ attribute :home_pts_q2, Shale::Type::Integer
144
+
145
+ # @!attribute [rw] home_pts_q3
146
+ # Returns home team Q3 points
147
+ # @api public
148
+ # @example
149
+ # summary.home_pts_q3 #=> 25
150
+ # @return [Integer] Q3 points
151
+ attribute :home_pts_q3, Shale::Type::Integer
152
+
153
+ # @!attribute [rw] home_pts_q4
154
+ # Returns home team Q4 points
155
+ # @api public
156
+ # @example
157
+ # summary.home_pts_q4 #=> 33
158
+ # @return [Integer] Q4 points
159
+ attribute :home_pts_q4, Shale::Type::Integer
160
+
161
+ # @!attribute [rw] home_pts_ot
162
+ # Returns home team OT points
163
+ # @api public
164
+ # @example
165
+ # summary.home_pts_ot #=> 0
166
+ # @return [Integer] OT points
167
+ attribute :home_pts_ot, Shale::Type::Integer
168
+
169
+ # @!attribute [rw] home_pts
170
+ # Returns home team total points
171
+ # @api public
172
+ # @example
173
+ # summary.home_pts #=> 118
174
+ # @return [Integer] total points
175
+ attribute :home_pts, Shale::Type::Integer
176
+
177
+ # @!attribute [rw] visitor_pts_q1
178
+ # Returns visitor team Q1 points
179
+ # @api public
180
+ # @example
181
+ # summary.visitor_pts_q1 #=> 25
182
+ # @return [Integer] Q1 points
183
+ attribute :visitor_pts_q1, Shale::Type::Integer
184
+
185
+ # @!attribute [rw] visitor_pts_q2
186
+ # Returns visitor team Q2 points
187
+ # @api public
188
+ # @example
189
+ # summary.visitor_pts_q2 #=> 28
190
+ # @return [Integer] Q2 points
191
+ attribute :visitor_pts_q2, Shale::Type::Integer
192
+
193
+ # @!attribute [rw] visitor_pts_q3
194
+ # Returns visitor team Q3 points
195
+ # @api public
196
+ # @example
197
+ # summary.visitor_pts_q3 #=> 30
198
+ # @return [Integer] Q3 points
199
+ attribute :visitor_pts_q3, Shale::Type::Integer
200
+
201
+ # @!attribute [rw] visitor_pts_q4
202
+ # Returns visitor team Q4 points
203
+ # @api public
204
+ # @example
205
+ # summary.visitor_pts_q4 #=> 26
206
+ # @return [Integer] Q4 points
207
+ attribute :visitor_pts_q4, Shale::Type::Integer
208
+
209
+ # @!attribute [rw] visitor_pts_ot
210
+ # Returns visitor team OT points
211
+ # @api public
212
+ # @example
213
+ # summary.visitor_pts_ot #=> 0
214
+ # @return [Integer] OT points
215
+ attribute :visitor_pts_ot, Shale::Type::Integer
216
+
217
+ # @!attribute [rw] visitor_pts
218
+ # Returns visitor team total points
219
+ # @api public
220
+ # @example
221
+ # summary.visitor_pts #=> 109
222
+ # @return [Integer] total points
223
+ attribute :visitor_pts, Shale::Type::Integer
224
+
225
+ # Returns the home team object
226
+ #
227
+ # @api public
228
+ # @example
229
+ # summary.home_team #=> #<NBA::Team>
230
+ # @return [Team, nil] the home team
231
+ def home_team
232
+ Teams.find(home_team_id)
233
+ end
234
+
235
+ # Returns the visitor team object
236
+ #
237
+ # @api public
238
+ # @example
239
+ # summary.visitor_team #=> #<NBA::Team>
240
+ # @return [Team, nil] the visitor team
241
+ def visitor_team
242
+ Teams.find(visitor_team_id)
243
+ end
244
+
245
+ # Returns the game object
246
+ #
247
+ # @api public
248
+ # @example
249
+ # summary.game #=> #<NBA::Game>
250
+ # @return [Game, nil] the game
251
+ def game
252
+ Games.find(game_id)
253
+ end
254
+
255
+ # Returns whether the game is final
256
+ #
257
+ # @api public
258
+ # @example
259
+ # summary.final? #=> true
260
+ # @return [Boolean] true if final
261
+ def final?
262
+ game_status_id.eql?(3)
263
+ end
264
+
265
+ # Returns whether the game is in progress
266
+ #
267
+ # @api public
268
+ # @example
269
+ # summary.in_progress? #=> false
270
+ # @return [Boolean] true if in progress
271
+ def in_progress?
272
+ game_status_id.eql?(2)
273
+ end
274
+
275
+ # Returns whether the game has not started
276
+ #
277
+ # @api public
278
+ # @example
279
+ # summary.scheduled? #=> false
280
+ # @return [Boolean] true if scheduled
281
+ def scheduled?
282
+ game_status_id.eql?(1)
283
+ end
284
+ end
285
+ end
@@ -0,0 +1,202 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "box_score_summary"
4
+ require_relative "utils"
5
+
6
+ module NBA
7
+ # Provides methods to retrieve game summary information
8
+ module BoxScoreSummaryV2
9
+ # Result set name for game summary
10
+ # @return [String] the result set name
11
+ GAME_SUMMARY = "GameSummary".freeze
12
+
13
+ # Result set name for line score
14
+ # @return [String] the result set name
15
+ LINE_SCORE = "LineScore".freeze
16
+
17
+ # Result set name for officials
18
+ # @return [String] the result set name
19
+ OFFICIALS = "Officials".freeze
20
+
21
+ # Result set name for other stats
22
+ # @return [String] the result set name
23
+ OTHER_STATS = "OtherStats".freeze
24
+
25
+ # Retrieves game summary information
26
+ #
27
+ # @api public
28
+ # @example
29
+ # summary = NBA::BoxScoreSummaryV2.find(game: "0022400001")
30
+ # puts "#{summary.home_team.full_name} #{summary.home_pts} - #{summary.visitor_pts} #{summary.visitor_team.full_name}"
31
+ # @param game [String, Game] the game ID or Game object
32
+ # @param client [Client] the API client to use
33
+ # @return [BoxScoreSummary, nil] the game summary
34
+ def self.find(game:, client: CLIENT)
35
+ game_id = Utils.extract_id(game)
36
+ path = "boxscoresummaryv2?GameID=#{game_id}"
37
+ response = client.get(path)
38
+ parse_response(response, game_id)
39
+ end
40
+
41
+ # Parses the API response
42
+ # @api private
43
+ # @param response [String, nil] the JSON response
44
+ # @param game_id [String] the game ID
45
+ # @return [BoxScoreSummary, nil] the game summary
46
+ def self.parse_response(response, game_id)
47
+ return unless response
48
+
49
+ data = JSON.parse(response)
50
+ game_summary = find_result_set(data, GAME_SUMMARY)
51
+ return unless game_summary
52
+
53
+ line_scores = find_result_set(data, LINE_SCORE)
54
+ officials = find_result_set(data, OFFICIALS)
55
+ other_stats = find_result_set(data, OTHER_STATS)
56
+
57
+ build_summary(game_summary, line_scores, officials, other_stats, game_id)
58
+ end
59
+ private_class_method :parse_response
60
+
61
+ # Finds a result set by name
62
+ # @api private
63
+ # @param data [Hash] the parsed JSON
64
+ # @param name [String] the result set name
65
+ # @return [Hash, nil] the result set
66
+ def self.find_result_set(data, name)
67
+ result_sets = data["resultSets"]
68
+ return unless result_sets
69
+
70
+ result_sets.find { |rs| rs.fetch("name").eql?(name) }
71
+ end
72
+ private_class_method :find_result_set
73
+
74
+ # Builds the summary object
75
+ # @api private
76
+ # @param game_summary [Hash] game summary result set
77
+ # @param line_scores [Hash] line score result set
78
+ # @param officials [Hash] officials result set
79
+ # @param other_stats [Hash] other stats result set
80
+ # @param game_id [String] the game ID
81
+ # @return [BoxScoreSummary, nil] the summary
82
+ def self.build_summary(game_summary, line_scores, officials, other_stats, game_id)
83
+ summary_row = extract_first_row(game_summary)
84
+ return unless summary_row
85
+
86
+ home_line, visitor_line = extract_line_scores(line_scores)
87
+ attrs = game_attributes(summary_row, game_id)
88
+ attrs = attrs.merge(home_score_attributes(home_line))
89
+ attrs = attrs.merge(visitor_score_attributes(visitor_line))
90
+ attrs = attrs.merge(officials: extract_officials(officials))
91
+ attrs = attrs.merge(other_attributes(extract_other_stats(other_stats)))
92
+ BoxScoreSummary.new(**attrs)
93
+ end
94
+ private_class_method :build_summary
95
+
96
+ # Extracts the first row from a result set
97
+ # @api private
98
+ # @param result_set [Hash] the result set
99
+ # @return [Hash, nil] the first row as a hash
100
+ def self.extract_first_row(result_set)
101
+ headers = result_set["headers"]
102
+ row = result_set.dig("rowSet", 0)
103
+ return unless headers && row
104
+
105
+ headers.zip(row).to_h
106
+ end
107
+ private_class_method :extract_first_row
108
+
109
+ # Extracts line scores for home and visitor
110
+ # @api private
111
+ # @param line_scores [Hash] line score result set
112
+ # @return [Array<Hash, Hash>] home and visitor line scores
113
+ def self.extract_line_scores(line_scores)
114
+ return [{}, {}] unless line_scores
115
+
116
+ headers = line_scores["headers"]
117
+ rows = line_scores["rowSet"]
118
+ return [{}, {}] unless headers && rows && rows.size >= 2
119
+
120
+ [headers.zip(rows.fetch(1)).to_h, headers.zip(rows.fetch(0)).to_h]
121
+ end
122
+ private_class_method :extract_line_scores
123
+
124
+ # Extracts official names
125
+ # @api private
126
+ # @param officials [Hash] officials result set
127
+ # @return [Array<String>] official names
128
+ def self.extract_officials(officials)
129
+ return [] unless officials
130
+
131
+ headers = officials["headers"]
132
+ rows = officials["rowSet"]
133
+ return [] unless headers && rows
134
+
135
+ first_name_idx = headers.index("FIRST_NAME")
136
+ last_name_idx = headers.index("LAST_NAME")
137
+ return [] unless first_name_idx && last_name_idx
138
+
139
+ rows.map { |row| "#{row.fetch(first_name_idx)} #{row.fetch(last_name_idx)}" }
140
+ end
141
+ private_class_method :extract_officials
142
+
143
+ # Extracts other stats
144
+ # @api private
145
+ # @param other_stats [Hash] other stats result set
146
+ # @return [Hash] other stats hash
147
+ def self.extract_other_stats(other_stats)
148
+ return {} unless other_stats
149
+
150
+ headers = other_stats["headers"]
151
+ row = other_stats.dig("rowSet", 0)
152
+ return {} unless headers && row
153
+
154
+ headers.zip(row).to_h
155
+ end
156
+ private_class_method :extract_other_stats
157
+
158
+ # Extracts game attributes
159
+ # @api private
160
+ # @param data [Hash] the summary data
161
+ # @param game_id [String] the game ID
162
+ # @return [Hash] game attributes
163
+ def self.game_attributes(data, game_id)
164
+ {game_id: game_id, game_date: data.fetch("GAME_DATE_EST"), game_status_id: data.fetch("GAME_STATUS_ID"),
165
+ game_status_text: data.fetch("GAME_STATUS_TEXT"), home_team_id: data.fetch("HOME_TEAM_ID"),
166
+ visitor_team_id: data.fetch("VISITOR_TEAM_ID"), season: data.fetch("SEASON"),
167
+ live_period: data.fetch("LIVE_PERIOD"), live_pc_time: data.fetch("LIVE_PC_TIME"),
168
+ attendance: data.fetch("ATTENDANCE"), game_time: data.fetch("GAME_TIME")}
169
+ end
170
+ private_class_method :game_attributes
171
+
172
+ # Extracts home score attributes
173
+ # @api private
174
+ # @param data [Hash] the line score data
175
+ # @return [Hash] home score attributes
176
+ def self.home_score_attributes(data)
177
+ {home_pts_q1: data["PTS_QTR1"], home_pts_q2: data["PTS_QTR2"], home_pts_q3: data["PTS_QTR3"],
178
+ home_pts_q4: data["PTS_QTR4"], home_pts_ot: data["PTS_OT1"], home_pts: data["PTS"]}
179
+ end
180
+ private_class_method :home_score_attributes
181
+
182
+ # Extracts visitor score attributes
183
+ # @api private
184
+ # @param data [Hash] the line score data
185
+ # @return [Hash] visitor score attributes
186
+ def self.visitor_score_attributes(data)
187
+ {visitor_pts_q1: data["PTS_QTR1"], visitor_pts_q2: data["PTS_QTR2"],
188
+ visitor_pts_q3: data["PTS_QTR3"], visitor_pts_q4: data["PTS_QTR4"],
189
+ visitor_pts_ot: data["PTS_OT1"], visitor_pts: data["PTS"]}
190
+ end
191
+ private_class_method :visitor_score_attributes
192
+
193
+ # Extracts other stats attributes
194
+ # @api private
195
+ # @param data [Hash] the other stats data
196
+ # @return [Hash] other stats attributes
197
+ def self.other_attributes(data)
198
+ {lead_changes: data["LEAD_CHANGES"], times_tied: data["TIMES_TIED"], arena: data["ARENA"]}
199
+ end
200
+ private_class_method :other_attributes
201
+ end
202
+ end
@@ -0,0 +1,120 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "box_score_summary_v3_data"
4
+ require_relative "utils"
5
+
6
+ module NBA
7
+ # Provides methods to retrieve game summary information using V3 API
8
+ module BoxScoreSummaryV3
9
+ # Result set name for box score summary
10
+ # @return [String] the result set name
11
+ BOX_SCORE_SUMMARY = "boxScoreSummary".freeze
12
+
13
+ # Retrieves game summary information
14
+ #
15
+ # @api public
16
+ # @example
17
+ # summary = NBA::BoxScoreSummaryV3.find(game: "0022400001")
18
+ # puts "#{summary.home_team_name} #{summary.home_pts} - #{summary.away_pts} #{summary.away_team_name}"
19
+ # @param game [String, Game] the game ID or Game object
20
+ # @param client [Client] the API client to use
21
+ # @return [BoxScoreSummaryV3Data, nil] the game summary
22
+ def self.find(game:, client: CLIENT)
23
+ game_id = Utils.extract_id(game)
24
+ response = client.get("boxscoresummaryv3?GameID=#{game_id}")
25
+ parse_response(response, game_id)
26
+ end
27
+
28
+ # Parses the API response
29
+ # @api private
30
+ # @return [BoxScoreSummaryV3Data, nil] the game summary
31
+ def self.parse_response(response, game_id)
32
+ return unless response
33
+
34
+ box_score = JSON.parse(response)[BOX_SCORE_SUMMARY]
35
+ build_summary(box_score, game_id) if box_score
36
+ end
37
+ private_class_method :parse_response
38
+
39
+ # Builds the summary object
40
+ # @api private
41
+ # @return [BoxScoreSummaryV3Data] the summary
42
+ def self.build_summary(box_score, game_id)
43
+ attrs = game_attributes(box_score, game_id).merge(arena_attributes(box_score))
44
+ attrs.merge!(team_attributes(box_score, "homeTeam", "home"))
45
+ attrs.merge!(team_attributes(box_score, "awayTeam", "away"))
46
+ attrs.merge!(other_stats_attributes(box_score))
47
+ BoxScoreSummaryV3Data.new(**attrs, officials: extract_officials(box_score))
48
+ end
49
+ private_class_method :build_summary
50
+
51
+ # Extracts game attributes
52
+ # @api private
53
+ # @return [Hash] game attributes
54
+ def self.game_attributes(data, game_id)
55
+ {game_id: game_id, game_code: data["gameCode"], game_status: data["gameStatus"],
56
+ game_status_text: data["gameStatusText"], period: data["period"],
57
+ game_clock: data["gameClock"], game_time_utc: data["gameTimeUTC"],
58
+ game_et: data["gameEt"], duration: data["duration"],
59
+ attendance: data["attendance"], sellout: data["sellout"]}
60
+ end
61
+ private_class_method :game_attributes
62
+
63
+ # Extracts arena attributes
64
+ # @api private
65
+ # @return [Hash] arena attributes
66
+ def self.arena_attributes(data)
67
+ arena = data.fetch("arena", {})
68
+ {arena_id: arena["arenaId"], arena_name: arena["arenaName"],
69
+ arena_city: arena["arenaCity"], arena_state: arena["arenaState"],
70
+ arena_country: arena["arenaCountry"], arena_timezone: arena["arenaTimezone"]}
71
+ end
72
+ private_class_method :arena_attributes
73
+
74
+ # Extracts team attributes for home or away team
75
+ # @api private
76
+ # @return [Hash] team attributes
77
+ def self.team_attributes(data, team_key, prefix)
78
+ team = data.fetch(team_key, {})
79
+ {"#{prefix}_team_id": team["teamId"], "#{prefix}_team_name": team["teamName"],
80
+ "#{prefix}_team_city": team["teamCity"], "#{prefix}_team_tricode": team["teamTricode"],
81
+ "#{prefix}_team_slug": team["teamSlug"], "#{prefix}_team_wins": team["teamWins"],
82
+ "#{prefix}_team_losses": team["teamLosses"], "#{prefix}_pts": team["score"],
83
+ "#{prefix}_pts_q1": extract_period_score(team, 1), "#{prefix}_pts_q2": extract_period_score(team, 2),
84
+ "#{prefix}_pts_q3": extract_period_score(team, 3), "#{prefix}_pts_q4": extract_period_score(team, 4)}
85
+ end
86
+ private_class_method :team_attributes
87
+
88
+ # Extracts period score from team data
89
+ # @api private
90
+ # @return [Integer, nil] period score
91
+ def self.extract_period_score(team, period)
92
+ periods = team["periods"]
93
+ return unless periods
94
+
95
+ period_data = periods.find { |p| p["period"].eql?(period) }
96
+ period_data&.[]("score")
97
+ end
98
+ private_class_method :extract_period_score
99
+
100
+ # Extracts other stats attributes
101
+ # @api private
102
+ # @return [Hash] other stats attributes
103
+ def self.other_stats_attributes(data)
104
+ {lead_changes: data["leadChanges"], times_tied: data["timesTied"],
105
+ largest_lead: data["largestLead"]}
106
+ end
107
+ private_class_method :other_stats_attributes
108
+
109
+ # Extracts official names
110
+ # @api private
111
+ # @return [Array<String>] official names
112
+ def self.extract_officials(data)
113
+ officials = data["officials"]
114
+ return [] unless officials
115
+
116
+ officials.filter_map { |o| "#{o.fetch("firstName")} #{o.fetch("familyName")}" if o["firstName"] && o["familyName"] }
117
+ end
118
+ private_class_method :extract_officials
119
+ end
120
+ end