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,185 @@
1
+ require "shale"
2
+ require "equalizer"
3
+
4
+ module NBA
5
+ # Represents a player's four factors box score statistics for a game
6
+ class BoxScoreFourFactorsPlayerStat < Shale::Mapper
7
+ include Equalizer.new(:game_id, :player_id)
8
+
9
+ # @!attribute [rw] game_id
10
+ # Returns the game ID
11
+ # @api public
12
+ # @example
13
+ # stat.game_id #=> "0022400350"
14
+ # @return [String] the game ID
15
+ attribute :game_id, Shale::Type::String
16
+
17
+ # @!attribute [rw] team_id
18
+ # Returns the team ID
19
+ # @api public
20
+ # @example
21
+ # stat.team_id #=> 1610612744
22
+ # @return [Integer] the team ID
23
+ attribute :team_id, Shale::Type::Integer
24
+
25
+ # @!attribute [rw] team_abbreviation
26
+ # Returns the team abbreviation
27
+ # @api public
28
+ # @example
29
+ # stat.team_abbreviation #=> "GSW"
30
+ # @return [String] the team abbreviation
31
+ attribute :team_abbreviation, Shale::Type::String
32
+
33
+ # @!attribute [rw] team_city
34
+ # Returns the team city
35
+ # @api public
36
+ # @example
37
+ # stat.team_city #=> "Golden State"
38
+ # @return [String] the team city
39
+ attribute :team_city, Shale::Type::String
40
+
41
+ # @!attribute [rw] player_id
42
+ # Returns the player ID
43
+ # @api public
44
+ # @example
45
+ # stat.player_id #=> 201939
46
+ # @return [Integer] the player ID
47
+ attribute :player_id, Shale::Type::Integer
48
+
49
+ # @!attribute [rw] player_name
50
+ # Returns the player name
51
+ # @api public
52
+ # @example
53
+ # stat.player_name #=> "Stephen Curry"
54
+ # @return [String] the player name
55
+ attribute :player_name, Shale::Type::String
56
+
57
+ # @!attribute [rw] start_position
58
+ # Returns the starting position
59
+ # @api public
60
+ # @example
61
+ # stat.start_position #=> "G"
62
+ # @return [String] the starting position
63
+ attribute :start_position, Shale::Type::String
64
+
65
+ # @!attribute [rw] comment
66
+ # Returns any comment (e.g., "DNP - Rest")
67
+ # @api public
68
+ # @example
69
+ # stat.comment #=> "DNP - Rest"
70
+ # @return [String] the comment
71
+ attribute :comment, Shale::Type::String
72
+
73
+ # @!attribute [rw] min
74
+ # Returns minutes played
75
+ # @api public
76
+ # @example
77
+ # stat.min #=> "32:45"
78
+ # @return [String] the minutes played
79
+ attribute :min, Shale::Type::String
80
+
81
+ # @!attribute [rw] efg_pct
82
+ # Returns effective field goal percentage
83
+ # @api public
84
+ # @example
85
+ # stat.efg_pct #=> 0.625
86
+ # @return [Float] the effective field goal percentage
87
+ attribute :efg_pct, Shale::Type::Float
88
+
89
+ # @!attribute [rw] fta_rate
90
+ # Returns free throw attempt rate
91
+ # @api public
92
+ # @example
93
+ # stat.fta_rate #=> 0.45
94
+ # @return [Float] the free throw attempt rate
95
+ attribute :fta_rate, Shale::Type::Float
96
+
97
+ # @!attribute [rw] tov_pct
98
+ # Returns turnover percentage
99
+ # @api public
100
+ # @example
101
+ # stat.tov_pct #=> 12.3
102
+ # @return [Float] the turnover percentage
103
+ attribute :tov_pct, Shale::Type::Float
104
+
105
+ # @!attribute [rw] oreb_pct
106
+ # Returns offensive rebound percentage
107
+ # @api public
108
+ # @example
109
+ # stat.oreb_pct #=> 3.2
110
+ # @return [Float] the offensive rebound percentage
111
+ attribute :oreb_pct, Shale::Type::Float
112
+
113
+ # @!attribute [rw] opp_efg_pct
114
+ # Returns opponent effective field goal percentage
115
+ # @api public
116
+ # @example
117
+ # stat.opp_efg_pct #=> 0.485
118
+ # @return [Float] the opponent effective field goal percentage
119
+ attribute :opp_efg_pct, Shale::Type::Float
120
+
121
+ # @!attribute [rw] opp_fta_rate
122
+ # Returns opponent free throw attempt rate
123
+ # @api public
124
+ # @example
125
+ # stat.opp_fta_rate #=> 0.28
126
+ # @return [Float] the opponent free throw attempt rate
127
+ attribute :opp_fta_rate, Shale::Type::Float
128
+
129
+ # @!attribute [rw] opp_tov_pct
130
+ # Returns opponent turnover percentage
131
+ # @api public
132
+ # @example
133
+ # stat.opp_tov_pct #=> 15.6
134
+ # @return [Float] the opponent turnover percentage
135
+ attribute :opp_tov_pct, Shale::Type::Float
136
+
137
+ # @!attribute [rw] opp_oreb_pct
138
+ # Returns opponent offensive rebound percentage
139
+ # @api public
140
+ # @example
141
+ # stat.opp_oreb_pct #=> 22.5
142
+ # @return [Float] the opponent offensive rebound percentage
143
+ attribute :opp_oreb_pct, Shale::Type::Float
144
+
145
+ # Returns the player object
146
+ #
147
+ # @api public
148
+ # @example
149
+ # stat.player #=> #<NBA::Player>
150
+ # @return [Player, nil] the player object
151
+ def player
152
+ Players.find(player_id)
153
+ end
154
+
155
+ # Returns the team object
156
+ #
157
+ # @api public
158
+ # @example
159
+ # stat.team #=> #<NBA::Team>
160
+ # @return [Team, nil] the team object
161
+ def team
162
+ Teams.find(team_id)
163
+ end
164
+
165
+ # Returns whether the player started the game
166
+ #
167
+ # @api public
168
+ # @example
169
+ # stat.starter? #=> true
170
+ # @return [Boolean] true if the player started
171
+ def starter?
172
+ !start_position.nil? && !start_position.empty?
173
+ end
174
+
175
+ # Returns the game object for this box score
176
+ #
177
+ # @api public
178
+ # @example
179
+ # stat.game #=> #<NBA::Game>
180
+ # @return [Game, nil] the game object
181
+ def game
182
+ Games.find(game_id)
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,141 @@
1
+ require "shale"
2
+ require "equalizer"
3
+
4
+ module NBA
5
+ # Represents a team's four factors box score statistics for a game
6
+ class BoxScoreFourFactorsTeamStat < Shale::Mapper
7
+ include Equalizer.new(:game_id, :team_id)
8
+
9
+ # @!attribute [rw] game_id
10
+ # Returns the game ID
11
+ # @api public
12
+ # @example
13
+ # stat.game_id #=> "0022400350"
14
+ # @return [String] the game ID
15
+ attribute :game_id, Shale::Type::String
16
+
17
+ # @!attribute [rw] team_id
18
+ # Returns the team ID
19
+ # @api public
20
+ # @example
21
+ # stat.team_id #=> 1610612744
22
+ # @return [Integer] the team ID
23
+ attribute :team_id, Shale::Type::Integer
24
+
25
+ # @!attribute [rw] team_name
26
+ # Returns the team name
27
+ # @api public
28
+ # @example
29
+ # stat.team_name #=> "Warriors"
30
+ # @return [String] the team name
31
+ attribute :team_name, Shale::Type::String
32
+
33
+ # @!attribute [rw] team_abbreviation
34
+ # Returns the team abbreviation
35
+ # @api public
36
+ # @example
37
+ # stat.team_abbreviation #=> "GSW"
38
+ # @return [String] the team abbreviation
39
+ attribute :team_abbreviation, Shale::Type::String
40
+
41
+ # @!attribute [rw] team_city
42
+ # Returns the team city
43
+ # @api public
44
+ # @example
45
+ # stat.team_city #=> "Golden State"
46
+ # @return [String] the team city
47
+ attribute :team_city, Shale::Type::String
48
+
49
+ # @!attribute [rw] min
50
+ # Returns total minutes played
51
+ # @api public
52
+ # @example
53
+ # stat.min #=> "240:00"
54
+ # @return [String] the minutes
55
+ attribute :min, Shale::Type::String
56
+
57
+ # @!attribute [rw] efg_pct
58
+ # Returns effective field goal percentage
59
+ # @api public
60
+ # @example
61
+ # stat.efg_pct #=> 0.562
62
+ # @return [Float] the effective field goal percentage
63
+ attribute :efg_pct, Shale::Type::Float
64
+
65
+ # @!attribute [rw] fta_rate
66
+ # Returns free throw attempt rate
67
+ # @api public
68
+ # @example
69
+ # stat.fta_rate #=> 0.284
70
+ # @return [Float] the free throw attempt rate
71
+ attribute :fta_rate, Shale::Type::Float
72
+
73
+ # @!attribute [rw] tov_pct
74
+ # Returns turnover percentage
75
+ # @api public
76
+ # @example
77
+ # stat.tov_pct #=> 14.5
78
+ # @return [Float] the turnover percentage
79
+ attribute :tov_pct, Shale::Type::Float
80
+
81
+ # @!attribute [rw] oreb_pct
82
+ # Returns offensive rebound percentage
83
+ # @api public
84
+ # @example
85
+ # stat.oreb_pct #=> 22.2
86
+ # @return [Float] the offensive rebound percentage
87
+ attribute :oreb_pct, Shale::Type::Float
88
+
89
+ # @!attribute [rw] opp_efg_pct
90
+ # Returns opponent effective field goal percentage
91
+ # @api public
92
+ # @example
93
+ # stat.opp_efg_pct #=> 0.485
94
+ # @return [Float] the opponent effective field goal percentage
95
+ attribute :opp_efg_pct, Shale::Type::Float
96
+
97
+ # @!attribute [rw] opp_fta_rate
98
+ # Returns opponent free throw attempt rate
99
+ # @api public
100
+ # @example
101
+ # stat.opp_fta_rate #=> 0.310
102
+ # @return [Float] the opponent free throw attempt rate
103
+ attribute :opp_fta_rate, Shale::Type::Float
104
+
105
+ # @!attribute [rw] opp_tov_pct
106
+ # Returns opponent turnover percentage
107
+ # @api public
108
+ # @example
109
+ # stat.opp_tov_pct #=> 17.8
110
+ # @return [Float] the opponent turnover percentage
111
+ attribute :opp_tov_pct, Shale::Type::Float
112
+
113
+ # @!attribute [rw] opp_oreb_pct
114
+ # Returns opponent offensive rebound percentage
115
+ # @api public
116
+ # @example
117
+ # stat.opp_oreb_pct #=> 20.5
118
+ # @return [Float] the opponent offensive rebound percentage
119
+ attribute :opp_oreb_pct, Shale::Type::Float
120
+
121
+ # Returns the team object
122
+ #
123
+ # @api public
124
+ # @example
125
+ # stat.team #=> #<NBA::Team>
126
+ # @return [Team, nil] the team object
127
+ def team
128
+ Teams.find(team_id)
129
+ end
130
+
131
+ # Returns the game object for this box score
132
+ #
133
+ # @api public
134
+ # @example
135
+ # stat.game #=> #<NBA::Game>
136
+ # @return [Game, nil] the game object
137
+ def game
138
+ Games.find(game_id)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,133 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "box_score_four_factors_player_stat"
5
+ require_relative "box_score_four_factors_team_stat"
6
+ require_relative "box_score_v3_helpers"
7
+ require_relative "utils"
8
+
9
+ module NBA
10
+ # Provides methods to retrieve four factors box score statistics using V3 API
11
+ module BoxScoreFourFactorsV3
12
+ # @return [String] JSON key for four factors box score data
13
+ BOX_SCORE_KEY = "boxScoreFourFactors".freeze
14
+ # @return [String] JSON key for player statistics
15
+ PLAYER_STATS = "PlayerStats".freeze
16
+ # @return [String] JSON key for team statistics
17
+ TEAM_STATS = "TeamStats".freeze
18
+
19
+ # Retrieves four factors player box score stats for a game
20
+ #
21
+ # @api public
22
+ # @example
23
+ # stats = NBA::BoxScoreFourFactorsV3.player_stats(game: "0022400001")
24
+ # stats.each { |stat| puts "#{stat.player_name}: #{stat.efg_pct}" }
25
+ # @param game [String, Integer] the game ID
26
+ # @param start_period [Integer] the starting period
27
+ # @param end_period [Integer] the ending period
28
+ # @param client [Client] the API client to use
29
+ # @return [Collection] a collection of player four factors stats
30
+ def self.player_stats(game:, start_period: 0, end_period: 0, client: CLIENT)
31
+ game_id = Utils.extract_id(game)
32
+ response = client.get(build_path(game_id, start_period, end_period))
33
+ parse_player_response(response, game_id)
34
+ end
35
+
36
+ # Retrieves four factors team box score stats for a game
37
+ #
38
+ # @api public
39
+ # @example
40
+ # stats = NBA::BoxScoreFourFactorsV3.team_stats(game: "0022400001")
41
+ # stats.each { |stat| puts "#{stat.team_abbreviation}: #{stat.efg_pct}" }
42
+ # @param game [String, Integer] the game ID
43
+ # @param start_period [Integer] the starting period
44
+ # @param end_period [Integer] the ending period
45
+ # @param client [Client] the API client to use
46
+ # @return [Collection] a collection of team four factors stats
47
+ def self.team_stats(game:, start_period: 0, end_period: 0, client: CLIENT)
48
+ game_id = Utils.extract_id(game)
49
+ response = client.get(build_path(game_id, start_period, end_period))
50
+ parse_team_response(response, game_id)
51
+ end
52
+
53
+ # Builds the API request path
54
+ # @api private
55
+ # @return [String] the request path
56
+ def self.build_path(game_id, start_period, end_period)
57
+ "boxscorefourfactorsv3?GameID=#{game_id}&StartPeriod=#{start_period}" \
58
+ "&EndPeriod=#{end_period}&StartRange=0&EndRange=0&RangeType=0"
59
+ end
60
+ private_class_method :build_path
61
+
62
+ # Parses the API response into player stat objects
63
+ # @api private
64
+ # @return [Collection] collection of player stats
65
+ def self.parse_player_response(response, game_id)
66
+ return Collection.new unless response
67
+
68
+ data = JSON.parse(response)
69
+ players = BoxScoreV3Helpers.extract_players(data, BOX_SCORE_KEY)
70
+ return Collection.new unless players
71
+
72
+ Collection.new(players.map { |p| build_player_stat(p, game_id) })
73
+ end
74
+ private_class_method :parse_player_response
75
+
76
+ # Parses the API response into team stat objects
77
+ # @api private
78
+ # @return [Collection] collection of team stats
79
+ def self.parse_team_response(response, game_id)
80
+ return Collection.new unless response
81
+
82
+ data = JSON.parse(response)
83
+ teams = BoxScoreV3Helpers.extract_teams(data, BOX_SCORE_KEY)
84
+ return Collection.new unless teams
85
+
86
+ Collection.new(teams.map { |t| build_team_stat(t, game_id) })
87
+ end
88
+ private_class_method :parse_team_response
89
+
90
+ # Builds a player stat object from raw data
91
+ # @api private
92
+ # @return [BoxScoreFourFactorsPlayerStat] the player stat object
93
+ def self.build_player_stat(player, game_id)
94
+ stats = player.fetch("statistics", {})
95
+ BoxScoreFourFactorsPlayerStat.new(
96
+ **BoxScoreV3Helpers.player_identity(player, game_id),
97
+ min: stats["minutes"],
98
+ **four_factors_stats(stats)
99
+ )
100
+ end
101
+ private_class_method :build_player_stat
102
+
103
+ # Builds a team stat object from raw data
104
+ # @api private
105
+ # @return [BoxScoreFourFactorsTeamStat] the team stat object
106
+ def self.build_team_stat(team, game_id)
107
+ stats = team.fetch("statistics", {})
108
+ BoxScoreFourFactorsTeamStat.new(
109
+ **BoxScoreV3Helpers.team_identity(team, game_id),
110
+ min: stats["minutes"],
111
+ **four_factors_stats(stats)
112
+ )
113
+ end
114
+ private_class_method :build_team_stat
115
+
116
+ # Extracts four factors statistics from raw data
117
+ # @api private
118
+ # @return [Hash] four factors statistics
119
+ def self.four_factors_stats(stats)
120
+ {
121
+ efg_pct: stats["effectiveFieldGoalPercentage"],
122
+ fta_rate: stats["freeThrowAttemptRate"],
123
+ tov_pct: stats["teamTurnoverPercentage"],
124
+ oreb_pct: stats["offensiveReboundPercentage"],
125
+ opp_efg_pct: stats["oppEffectiveFieldGoalPercentage"],
126
+ opp_fta_rate: stats["oppFreeThrowAttemptRate"],
127
+ opp_tov_pct: stats["oppTurnoverPercentage"],
128
+ opp_oreb_pct: stats["oppOffensiveReboundPercentage"]
129
+ }
130
+ end
131
+ private_class_method :four_factors_stats
132
+ end
133
+ end
@@ -0,0 +1,226 @@
1
+ require "json"
2
+ require_relative "client"
3
+ require_relative "collection"
4
+ require_relative "box_score_hustle_player_stat"
5
+ require_relative "box_score_hustle_team_stat"
6
+ require_relative "utils"
7
+
8
+ module NBA
9
+ # Provides methods to retrieve hustle statistics for a game
10
+ module BoxScoreHustle
11
+ # Result set name for player stats
12
+ # @return [String] the result set name
13
+ PLAYER_STATS = "PlayerStats".freeze
14
+
15
+ # Result set name for team stats
16
+ # @return [String] the result set name
17
+ TEAM_STATS = "TeamStats".freeze
18
+
19
+ # Retrieves hustle statistics for players in a game
20
+ #
21
+ # @api public
22
+ # @example
23
+ # stats = NBA::BoxScoreHustle.player_stats(game: "0022400001")
24
+ # stats.each { |s| puts "#{s.player_name}: #{s.deflections} deflections" }
25
+ # @param game [String, Game] the game ID or Game object
26
+ # @param client [Client] the API client to use
27
+ # @return [Collection] a collection of player hustle stats
28
+ def self.player_stats(game:, client: CLIENT)
29
+ game_id = Utils.extract_id(game)
30
+ path = "boxscorehustlev2?GameID=#{game_id}"
31
+ response = client.get(path)
32
+ parse_player_response(response, game_id)
33
+ end
34
+
35
+ # Retrieves hustle statistics for teams in a game
36
+ #
37
+ # @api public
38
+ # @example
39
+ # stats = NBA::BoxScoreHustle.team_stats(game: "0022400001")
40
+ # stats.each { |s| puts "#{s.team_name}: #{s.deflections} deflections" }
41
+ # @param game [String, Game] the game ID or Game object
42
+ # @param client [Client] the API client to use
43
+ # @return [Collection] a collection of team hustle stats
44
+ def self.team_stats(game:, client: CLIENT)
45
+ game_id = Utils.extract_id(game)
46
+ path = "boxscorehustlev2?GameID=#{game_id}"
47
+ response = client.get(path)
48
+ parse_team_response(response, game_id)
49
+ end
50
+
51
+ # Parses player stats response
52
+ # @api private
53
+ # @param response [String, nil] the JSON response
54
+ # @param game_id [String] the game ID
55
+ # @return [Collection] collection of player stats
56
+ def self.parse_player_response(response, game_id)
57
+ return Collection.new unless response
58
+
59
+ data = JSON.parse(response)
60
+ result_set = find_result_set(data, PLAYER_STATS)
61
+ return Collection.new unless result_set
62
+
63
+ build_player_stats(result_set, game_id)
64
+ end
65
+ private_class_method :parse_player_response
66
+
67
+ # Parses team stats response
68
+ # @api private
69
+ # @param response [String, nil] the JSON response
70
+ # @param game_id [String] the game ID
71
+ # @return [Collection] collection of team stats
72
+ def self.parse_team_response(response, game_id)
73
+ return Collection.new unless response
74
+
75
+ data = JSON.parse(response)
76
+ result_set = find_result_set(data, TEAM_STATS)
77
+ return Collection.new unless result_set
78
+
79
+ build_team_stats(result_set, game_id)
80
+ end
81
+ private_class_method :parse_team_response
82
+
83
+ # Finds a result set by name
84
+ # @api private
85
+ # @param data [Hash] the parsed JSON
86
+ # @param name [String] the result set name
87
+ # @return [Hash, nil] the result set
88
+ def self.find_result_set(data, name)
89
+ result_sets = data["resultSets"]
90
+ return unless result_sets
91
+
92
+ result_sets.find { |rs| rs.fetch("name").eql?(name) }
93
+ end
94
+ private_class_method :find_result_set
95
+
96
+ # Builds player stats collection
97
+ # @api private
98
+ # @param result_set [Hash] the result set
99
+ # @param game_id [String] the game ID
100
+ # @return [Collection] collection of player stats
101
+ def self.build_player_stats(result_set, game_id)
102
+ headers = result_set["headers"]
103
+ rows = result_set["rowSet"]
104
+ return Collection.new unless headers && rows
105
+
106
+ stats = rows.map { |row| build_player_stat(headers, row, game_id) }
107
+ Collection.new(stats)
108
+ end
109
+ private_class_method :build_player_stats
110
+
111
+ # Builds team stats collection
112
+ # @api private
113
+ # @param result_set [Hash] the result set
114
+ # @param game_id [String] the game ID
115
+ # @return [Collection] collection of team stats
116
+ def self.build_team_stats(result_set, game_id)
117
+ headers = result_set["headers"]
118
+ rows = result_set["rowSet"]
119
+ return Collection.new unless headers && rows
120
+
121
+ stats = rows.map { |row| build_team_stat(headers, row, game_id) }
122
+ Collection.new(stats)
123
+ end
124
+ private_class_method :build_team_stats
125
+
126
+ # Builds a player stat
127
+ # @api private
128
+ # @param headers [Array<String>] the headers
129
+ # @param row [Array] the row data
130
+ # @param game_id [String] the game ID
131
+ # @return [BoxScoreHustlePlayerStat] the player stat
132
+ def self.build_player_stat(headers, row, game_id)
133
+ data = headers.zip(row).to_h
134
+ BoxScoreHustlePlayerStat.new(**player_stat_attributes(data, game_id))
135
+ end
136
+ private_class_method :build_player_stat
137
+
138
+ # Builds a team stat
139
+ # @api private
140
+ # @param headers [Array<String>] the headers
141
+ # @param row [Array] the row data
142
+ # @param game_id [String] the game ID
143
+ # @return [BoxScoreHustleTeamStat] the team stat
144
+ def self.build_team_stat(headers, row, game_id)
145
+ data = headers.zip(row).to_h
146
+ BoxScoreHustleTeamStat.new(**team_stat_attributes(data, game_id))
147
+ end
148
+ private_class_method :build_team_stat
149
+
150
+ # Combines player stat attributes
151
+ # @api private
152
+ # @param data [Hash] the raw data
153
+ # @param game_id [String] the game ID
154
+ # @return [Hash] the combined attributes
155
+ def self.player_stat_attributes(data, game_id)
156
+ player_identity(data, game_id).merge(hustle_stats(data), loose_ball_stats(data), box_out_stats(data))
157
+ end
158
+ private_class_method :player_stat_attributes
159
+
160
+ # Combines team stat attributes
161
+ # @api private
162
+ # @param data [Hash] the raw data
163
+ # @param game_id [String] the game ID
164
+ # @return [Hash] the combined attributes
165
+ def self.team_stat_attributes(data, game_id)
166
+ team_identity(data, game_id).merge(hustle_stats(data), loose_ball_stats(data), box_out_stats(data))
167
+ end
168
+ private_class_method :team_stat_attributes
169
+
170
+ # Extracts player identity attributes
171
+ # @api private
172
+ # @param data [Hash] the raw data
173
+ # @param game_id [String] the game ID
174
+ # @return [Hash] identity attributes
175
+ def self.player_identity(data, game_id)
176
+ {game_id: game_id, team_id: data.fetch("TEAM_ID"), team_abbreviation: data.fetch("TEAM_ABBREVIATION"),
177
+ team_city: data.fetch("TEAM_CITY"), player_id: data.fetch("PLAYER_ID"), player_name: data.fetch("PLAYER_NAME"),
178
+ start_position: data.fetch("START_POSITION"), comment: data.fetch("COMMENT"), min: data.fetch("MIN"), pts: data.fetch("PTS")}
179
+ end
180
+ private_class_method :player_identity
181
+
182
+ # Extracts team identity attributes
183
+ # @api private
184
+ # @param data [Hash] the raw data
185
+ # @param game_id [String] the game ID
186
+ # @return [Hash] identity attributes
187
+ def self.team_identity(data, game_id)
188
+ {game_id: game_id, team_id: data.fetch("TEAM_ID"), team_name: data.fetch("TEAM_NAME"),
189
+ team_abbreviation: data.fetch("TEAM_ABBREVIATION"), team_city: data.fetch("TEAM_CITY"),
190
+ min: data.fetch("MIN"), pts: data.fetch("PTS")}
191
+ end
192
+ private_class_method :team_identity
193
+
194
+ # Extracts hustle stats
195
+ # @api private
196
+ # @param data [Hash] the raw data
197
+ # @return [Hash] hustle stats
198
+ def self.hustle_stats(data)
199
+ {contested_shots: data.fetch("CONTESTED_SHOTS"), contested_shots_2pt: data.fetch("CONTESTED_SHOTS_2PT"),
200
+ contested_shots_3pt: data.fetch("CONTESTED_SHOTS_3PT"), deflections: data.fetch("DEFLECTIONS"),
201
+ charges_drawn: data.fetch("CHARGES_DRAWN"), screen_assists: data.fetch("SCREEN_ASSISTS"),
202
+ screen_ast_pts: data.fetch("SCREEN_AST_PTS")}
203
+ end
204
+ private_class_method :hustle_stats
205
+
206
+ # Extracts loose ball stats
207
+ # @api private
208
+ # @param data [Hash] the raw data
209
+ # @return [Hash] loose ball stats
210
+ def self.loose_ball_stats(data)
211
+ {loose_balls_recovered: data.fetch("LOOSE_BALLS_RECOVERED"),
212
+ off_loose_balls_recovered: data.fetch("OFF_LOOSE_BALLS_RECOVERED"),
213
+ def_loose_balls_recovered: data.fetch("DEF_LOOSE_BALLS_RECOVERED")}
214
+ end
215
+ private_class_method :loose_ball_stats
216
+
217
+ # Extracts box out stats
218
+ # @api private
219
+ # @param data [Hash] the raw data
220
+ # @return [Hash] box out stats
221
+ def self.box_out_stats(data)
222
+ {box_outs: data.fetch("BOX_OUTS"), off_box_outs: data.fetch("OFF_BOX_OUTS"), def_box_outs: data.fetch("DEF_BOX_OUTS")}
223
+ end
224
+ private_class_method :box_out_stats
225
+ end
226
+ end