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.
- checksums.yaml +5 -5
- data/AGENTS.md +362 -0
- data/CHANGELOG.md +169 -0
- data/CLAUDE.md +1 -0
- data/LICENSE +21 -0
- data/README.md +501 -101
- data/bin/console +10 -0
- data/bin/setup +6 -0
- data/exe/nba +8 -0
- data/lib/nba/all_time_leader.rb +77 -0
- data/lib/nba/all_time_leaders.rb +185 -0
- data/lib/nba/assist_leader.rb +92 -0
- data/lib/nba/assist_leaders.rb +64 -0
- data/lib/nba/assist_tracker.rb +108 -0
- data/lib/nba/assist_tracker_entry.rb +206 -0
- data/lib/nba/award.rb +128 -0
- data/lib/nba/box_score.rb +2 -0
- data/lib/nba/box_score_advanced.rb +114 -0
- data/lib/nba/box_score_advanced_player_stat.rb +297 -0
- data/lib/nba/box_score_advanced_team_stat.rb +237 -0
- data/lib/nba/box_score_advanced_v3.rb +124 -0
- data/lib/nba/box_score_defensive_player_stat.rb +281 -0
- data/lib/nba/box_score_defensive_team_stat.rb +85 -0
- data/lib/nba/box_score_defensive_v2.rb +190 -0
- data/lib/nba/box_score_four_factors.rb +91 -0
- data/lib/nba/box_score_four_factors_player_stat.rb +185 -0
- data/lib/nba/box_score_four_factors_team_stat.rb +141 -0
- data/lib/nba/box_score_four_factors_v3.rb +133 -0
- data/lib/nba/box_score_hustle.rb +226 -0
- data/lib/nba/box_score_hustle_player_stat.rb +233 -0
- data/lib/nba/box_score_hustle_team_stat.rb +189 -0
- data/lib/nba/box_score_matchup_stat.rb +417 -0
- data/lib/nba/box_score_matchups_v3.rb +184 -0
- data/lib/nba/box_score_misc.rb +100 -0
- data/lib/nba/box_score_misc_player_stat.rb +217 -0
- data/lib/nba/box_score_misc_team_stat.rb +173 -0
- data/lib/nba/box_score_misc_v3.rb +163 -0
- data/lib/nba/box_score_player_stat.rb +273 -0
- data/lib/nba/box_score_player_track.rb +223 -0
- data/lib/nba/box_score_player_track_stat.rb +273 -0
- data/lib/nba/box_score_player_track_team_stat.rb +229 -0
- data/lib/nba/box_score_scoring.rb +103 -0
- data/lib/nba/box_score_scoring_player_stat.rb +241 -0
- data/lib/nba/box_score_scoring_team_stat.rb +197 -0
- data/lib/nba/box_score_scoring_v3.rb +170 -0
- data/lib/nba/box_score_similarity_score.rb +119 -0
- data/lib/nba/box_score_similarity_stat.rb +76 -0
- data/lib/nba/box_score_starter_bench_stat.rb +257 -0
- data/lib/nba/box_score_summary.rb +285 -0
- data/lib/nba/box_score_summary_v2.rb +202 -0
- data/lib/nba/box_score_summary_v3.rb +120 -0
- data/lib/nba/box_score_summary_v3_data.rb +419 -0
- data/lib/nba/box_score_team_stat.rb +229 -0
- data/lib/nba/box_score_traditional.rb +101 -0
- data/lib/nba/box_score_traditional_v3.rb +195 -0
- data/lib/nba/box_score_usage.rb +102 -0
- data/lib/nba/box_score_usage_player_stat.rb +265 -0
- data/lib/nba/box_score_usage_team_stat.rb +221 -0
- data/lib/nba/box_score_usage_v3.rb +169 -0
- data/lib/nba/box_score_v3_helpers.rb +144 -0
- data/lib/nba/career_stats.rb +217 -0
- data/lib/nba/cli/display/player_display.rb +98 -0
- data/lib/nba/cli/display.rb +178 -0
- data/lib/nba/cli/formatters/game_formatters.rb +86 -0
- data/lib/nba/cli/formatters/leaders_formatters.rb +26 -0
- data/lib/nba/cli/formatters/player_formatters.rb +52 -0
- data/lib/nba/cli/formatters/standings_formatters.rb +26 -0
- data/lib/nba/cli/formatters/team_formatters.rb +67 -0
- data/lib/nba/cli/formatters/time_formatters.rb +82 -0
- data/lib/nba/cli/formatters.rb +56 -0
- data/lib/nba/cli/helpers.rb +135 -0
- data/lib/nba/cli.rb +171 -20
- data/lib/nba/client.rb +35 -0
- data/lib/nba/collection.rb +89 -0
- data/lib/nba/college_player_stat.rb +200 -0
- data/lib/nba/common_player_info.rb +142 -0
- data/lib/nba/common_playoff_series.rb +90 -0
- data/lib/nba/common_team_years.rb +113 -0
- data/lib/nba/conference.rb +39 -0
- data/lib/nba/connection.rb +84 -0
- data/lib/nba/cume_stats_player.rb +358 -0
- data/lib/nba/cume_stats_player_game.rb +217 -0
- data/lib/nba/cume_stats_player_games.rb +99 -0
- data/lib/nba/cume_stats_player_games_entry.rb +25 -0
- data/lib/nba/cume_stats_player_total.rb +481 -0
- data/lib/nba/cume_stats_team.rb +349 -0
- data/lib/nba/cume_stats_team_games.rb +145 -0
- data/lib/nba/cume_stats_team_games_entry.rb +25 -0
- data/lib/nba/cume_stats_team_player.rb +485 -0
- data/lib/nba/cume_stats_team_total.rb +267 -0
- data/lib/nba/data.rb +73 -0
- data/lib/nba/defense_hub.rb +109 -0
- data/lib/nba/defense_hub_stat.rb +57 -0
- data/lib/nba/defensive_shot_stat.rb +102 -0
- data/lib/nba/division.rb +49 -0
- data/lib/nba/draft_board.rb +126 -0
- data/lib/nba/draft_board_pick.rb +173 -0
- data/lib/nba/draft_combine_anthro_measurement.rb +163 -0
- data/lib/nba/draft_combine_drill_result.rb +115 -0
- data/lib/nba/draft_combine_drill_results.rb +112 -0
- data/lib/nba/draft_combine_non_stationary_shooting.rb +268 -0
- data/lib/nba/draft_combine_non_stationary_shooting_result.rb +355 -0
- data/lib/nba/draft_combine_player_anthro.rb +133 -0
- data/lib/nba/draft_combine_spot_shooting.rb +243 -0
- data/lib/nba/draft_combine_spot_shooting_result.rb +419 -0
- data/lib/nba/draft_combine_stat.rb +211 -0
- data/lib/nba/draft_combine_stats.rb +160 -0
- data/lib/nba/draft_history.rb +142 -0
- data/lib/nba/draft_pick.rb +154 -0
- data/lib/nba/dunk_score_leader.rb +93 -0
- data/lib/nba/dunk_score_leaders.rb +77 -0
- data/lib/nba/estimated_metrics_stat.rb +152 -0
- data/lib/nba/fantasy_profile_stat.rb +142 -0
- data/lib/nba/fantasy_widget.rb +72 -0
- data/lib/nba/fantasy_widget_player.rb +98 -0
- data/lib/nba/found_game.rb +260 -0
- data/lib/nba/franchise.rb +136 -0
- data/lib/nba/franchise_history.rb +142 -0
- data/lib/nba/franchise_leader.rb +147 -0
- data/lib/nba/franchise_leaders.rb +162 -0
- data/lib/nba/franchise_player.rb +224 -0
- data/lib/nba/franchise_players.rb +147 -0
- data/lib/nba/game.rb +80 -64
- data/lib/nba/game_log.rb +349 -0
- data/lib/nba/game_rotation.rb +152 -0
- data/lib/nba/game_streak.rb +102 -0
- data/lib/nba/games.rb +46 -0
- data/lib/nba/home_page_leader.rb +99 -0
- data/lib/nba/home_page_leaders.rb +75 -0
- data/lib/nba/home_page_stat.rb +57 -0
- data/lib/nba/home_page_v2.rb +110 -0
- data/lib/nba/hustle_stats_box_score.rb +182 -0
- data/lib/nba/infographic_fan_duel_player.rb +139 -0
- data/lib/nba/infographic_fan_duel_player_stat.rb +311 -0
- data/lib/nba/ist_standing.rb +167 -0
- data/lib/nba/ist_standings.rb +81 -0
- data/lib/nba/leader.rb +103 -0
- data/lib/nba/leaders.rb +110 -0
- data/lib/nba/leaders_tile.rb +57 -0
- data/lib/nba/leaders_tiles.rb +90 -0
- data/lib/nba/league.rb +37 -0
- data/lib/nba/league_dash_lineup_stat.rb +270 -0
- data/lib/nba/league_dash_lineups.rb +177 -0
- data/lib/nba/league_dash_opp_pt_shot.rb +150 -0
- data/lib/nba/league_dash_player_bio_stat.rb +217 -0
- data/lib/nba/league_dash_player_bio_stats.rb +164 -0
- data/lib/nba/league_dash_player_clutch.rb +212 -0
- data/lib/nba/league_dash_player_clutch_stat.rb +271 -0
- data/lib/nba/league_dash_player_pt_shot.rb +152 -0
- data/lib/nba/league_dash_player_pt_shot_stat.rb +193 -0
- data/lib/nba/league_dash_player_shot_location_stat.rb +265 -0
- data/lib/nba/league_dash_player_shot_locations.rb +210 -0
- data/lib/nba/league_dash_player_stat.rb +306 -0
- data/lib/nba/league_dash_player_stats.rb +176 -0
- data/lib/nba/league_dash_pt_defend.rb +160 -0
- data/lib/nba/league_dash_pt_defend_stat.rb +145 -0
- data/lib/nba/league_dash_pt_stats.rb +152 -0
- data/lib/nba/league_dash_pt_stats_stat.rb +169 -0
- data/lib/nba/league_dash_pt_team_defend.rb +158 -0
- data/lib/nba/league_dash_pt_team_defend_stat.rb +110 -0
- data/lib/nba/league_dash_team_clutch.rb +211 -0
- data/lib/nba/league_dash_team_clutch_stat.rb +237 -0
- data/lib/nba/league_dash_team_pt_shot.rb +150 -0
- data/lib/nba/league_dash_team_pt_shot_stat.rb +166 -0
- data/lib/nba/league_dash_team_shot_location_stat.rb +230 -0
- data/lib/nba/league_dash_team_shot_locations.rb +208 -0
- data/lib/nba/league_dash_team_stat.rb +275 -0
- data/lib/nba/league_dash_team_stats.rb +172 -0
- data/lib/nba/league_game_finder.rb +170 -0
- data/lib/nba/league_game_log.rb +224 -0
- data/lib/nba/league_hustle_stats_player.rb +161 -0
- data/lib/nba/league_hustle_stats_player_stat.rb +253 -0
- data/lib/nba/league_hustle_stats_team.rb +157 -0
- data/lib/nba/league_hustle_stats_team_stat.rb +179 -0
- data/lib/nba/league_lineup_viz.rb +184 -0
- data/lib/nba/league_lineup_viz_stat.rb +214 -0
- data/lib/nba/league_player_on_details.rb +175 -0
- data/lib/nba/league_player_on_details_stat.rb +313 -0
- data/lib/nba/league_season_matchup_stat.rb +241 -0
- data/lib/nba/league_season_matchups.rb +181 -0
- data/lib/nba/league_standing.rb +284 -0
- data/lib/nba/league_standings.rb +159 -0
- data/lib/nba/league_wide_shot_stat.rb +62 -0
- data/lib/nba/live_action.rb +240 -0
- data/lib/nba/live_box_score.rb +143 -0
- data/lib/nba/live_connection.rb +84 -0
- data/lib/nba/live_game.rb +230 -0
- data/lib/nba/live_play_by_play.rb +120 -0
- data/lib/nba/live_player_stat.rb +276 -0
- data/lib/nba/live_scoreboard.rb +102 -0
- data/lib/nba/matchup_rollup.rb +98 -0
- data/lib/nba/matchups_rollup.rb +81 -0
- data/lib/nba/pass_stat.rb +209 -0
- data/lib/nba/play.rb +258 -0
- data/lib/nba/play_by_play.rb +85 -0
- data/lib/nba/play_by_play_v3.rb +91 -0
- data/lib/nba/play_type_stat.rb +206 -0
- data/lib/nba/player.rb +242 -24
- data/lib/nba/player_awards.rb +110 -0
- data/lib/nba/player_career_by_college.rb +86 -0
- data/lib/nba/player_career_by_college_rollup.rb +143 -0
- data/lib/nba/player_career_stats.rb +77 -0
- data/lib/nba/player_compare.rb +156 -0
- data/lib/nba/player_comparison_stat.rb +242 -0
- data/lib/nba/player_dash_pt_pass.rb +164 -0
- data/lib/nba/player_dash_pt_reb.rb +235 -0
- data/lib/nba/player_dash_pt_shot_defend.rb +119 -0
- data/lib/nba/player_dash_pt_shots.rb +279 -0
- data/lib/nba/player_dashboard.rb +259 -0
- data/lib/nba/player_dashboard_stat.rb +248 -0
- data/lib/nba/player_estimated_metrics.rb +84 -0
- data/lib/nba/player_fantasy_profile_bar_graph.rb +147 -0
- data/lib/nba/player_game_log.rb +72 -0
- data/lib/nba/player_game_logs.rb +117 -0
- data/lib/nba/player_game_streak_finder.rb +108 -0
- data/lib/nba/player_index.rb +135 -0
- data/lib/nba/player_index_entry.rb +266 -0
- data/lib/nba/player_info.rb +225 -0
- data/lib/nba/player_next_n_games.rb +64 -0
- data/lib/nba/player_profile_v2.rb +169 -0
- data/lib/nba/player_vs_player.rb +153 -0
- data/lib/nba/players.rb +107 -0
- data/lib/nba/playoff_matchup.rb +84 -0
- data/lib/nba/playoff_picture.rb +98 -0
- data/lib/nba/playoff_series.rb +76 -0
- data/lib/nba/position.rb +48 -0
- data/lib/nba/rebound_stat.rb +189 -0
- data/lib/nba/response_parser.rb +116 -0
- data/lib/nba/roster.rb +74 -0
- data/lib/nba/rotation_entry.rb +154 -0
- data/lib/nba/schedule.rb +183 -0
- data/lib/nba/schedule_international.rb +182 -0
- data/lib/nba/scheduled_game.rb +240 -0
- data/lib/nba/scoreboard.rb +183 -0
- data/lib/nba/scoreboard_v3.rb +104 -0
- data/lib/nba/shot.rb +208 -0
- data/lib/nba/shot_chart.rb +75 -0
- data/lib/nba/shot_chart_league_wide.rb +102 -0
- data/lib/nba/shot_chart_lineup_detail.rb +109 -0
- data/lib/nba/shot_stat.rb +174 -0
- data/lib/nba/standing.rb +129 -0
- data/lib/nba/standings.rb +75 -0
- data/lib/nba/static.rb +107 -0
- data/lib/nba/synergy_play_types.rb +211 -0
- data/lib/nba/team.rb +203 -127
- data/lib/nba/team_and_players_vs_players.rb +227 -0
- data/lib/nba/team_and_players_vs_players_stat.rb +155 -0
- data/lib/nba/team_dash_pt_pass.rb +157 -0
- data/lib/nba/team_dash_pt_reb.rb +216 -0
- data/lib/nba/team_dash_pt_shots.rb +244 -0
- data/lib/nba/team_dashboard.rb +275 -0
- data/lib/nba/team_dashboard_stat.rb +248 -0
- data/lib/nba/team_detail.rb +117 -0
- data/lib/nba/team_details.rb +173 -0
- data/lib/nba/team_estimated_metrics.rb +91 -0
- data/lib/nba/team_estimated_metrics_stat.rb +146 -0
- data/lib/nba/team_game_log.rb +143 -0
- data/lib/nba/team_game_log_entry.rb +246 -0
- data/lib/nba/team_game_log_stat.rb +275 -0
- data/lib/nba/team_game_logs.rb +163 -0
- data/lib/nba/team_game_streak.rb +111 -0
- data/lib/nba/team_game_streak_finder.rb +109 -0
- data/lib/nba/team_historical_leader.rb +207 -0
- data/lib/nba/team_historical_leaders.rb +98 -0
- data/lib/nba/team_historical_record.rb +139 -0
- data/lib/nba/team_info.rb +150 -0
- data/lib/nba/team_info_common.rb +177 -0
- data/lib/nba/team_on_off_overall_stat.rb +477 -0
- data/lib/nba/team_on_off_player_stat.rb +523 -0
- data/lib/nba/team_on_off_player_summary.rb +135 -0
- data/lib/nba/team_pass_stat.rb +183 -0
- data/lib/nba/team_player_dashboard.rb +212 -0
- data/lib/nba/team_player_on_off_details.rb +218 -0
- data/lib/nba/team_player_on_off_summary.rb +214 -0
- data/lib/nba/team_player_stat.rb +275 -0
- data/lib/nba/team_rebound_stat.rb +189 -0
- data/lib/nba/team_season_rank.rb +110 -0
- data/lib/nba/team_shot_stat.rb +173 -0
- data/lib/nba/team_vs_player.rb +151 -0
- data/lib/nba/team_vs_player_stat.rb +157 -0
- data/lib/nba/team_year.rb +55 -0
- data/lib/nba/team_year_by_year_stats.rb +152 -0
- data/lib/nba/team_year_stat.rb +282 -0
- data/lib/nba/teams.rb +33 -0
- data/lib/nba/upcoming_game.rb +115 -0
- data/lib/nba/utils.rb +94 -0
- data/lib/nba/version.rb +5 -2
- data/lib/nba/video_detail.rb +103 -0
- data/lib/nba/video_details.rb +118 -0
- data/lib/nba/video_details_asset.rb +115 -0
- data/lib/nba/video_details_asset_entry.rb +91 -0
- data/lib/nba/video_event.rb +83 -0
- data/lib/nba/video_event_asset.rb +91 -0
- data/lib/nba/video_events.rb +106 -0
- data/lib/nba/video_events_asset.rb +107 -0
- data/lib/nba/video_status.rb +129 -0
- data/lib/nba/video_status_entry.rb +161 -0
- data/lib/nba/vs_player_stat.rb +156 -0
- data/lib/nba/win_probability.rb +117 -0
- data/lib/nba/win_probability_point.rb +140 -0
- data/lib/nba.rb +249 -5
- data/sig/equalizer.rbs +3 -0
- data/sig/nba.rbs +7297 -0
- data/sig/shale.rbs +24 -0
- data/sig/thor.rbs +19 -0
- metadata +324 -95
- data/.gitignore +0 -18
- data/.travis.yml +0 -22
- data/Gemfile +0 -23
- data/LICENSE.md +0 -22
- data/Rakefile +0 -18
- data/bin/nba +0 -7
- data/cache/teams.json +0 -16529
- data/lib/faraday_middleware/scrape_game.rb +0 -41
- data/lib/nba/request.rb +0 -37
- data/nba.gemspec +0 -28
- data/spec/fixtures/games.html +0 -785
- data/spec/fixtures/teams.json +0 -16529
- data/spec/game_spec.rb +0 -40
- data/spec/spec_helper.rb +0 -25
- data/spec/team_spec.rb +0 -93
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module NBA
|
|
2
|
+
class CLI < Thor
|
|
3
|
+
module Formatters
|
|
4
|
+
# Formatters for team-related output
|
|
5
|
+
module TeamFormatters
|
|
6
|
+
# Eastern Conference team abbreviations
|
|
7
|
+
#
|
|
8
|
+
# @api private
|
|
9
|
+
# @return [Array<String>]
|
|
10
|
+
EAST = %w[ATL BOS BKN CHA CHI CLE DET IND MIA MIL NYK ORL PHI TOR WAS].freeze
|
|
11
|
+
|
|
12
|
+
# Division mappings by team abbreviation
|
|
13
|
+
#
|
|
14
|
+
# @api private
|
|
15
|
+
# @return [Hash]
|
|
16
|
+
DIVISIONS = {
|
|
17
|
+
%w[BOS BKN NYK PHI TOR] => "Atlantic", %w[CHI CLE DET IND MIL] => "Central",
|
|
18
|
+
%w[ATL CHA MIA ORL WAS] => "Southeast", %w[DEN MIN OKC POR UTA] => "Northwest",
|
|
19
|
+
%w[GSW LAC LAL PHX SAC] => "Pacific", %w[DAL HOU MEM NOP SAS] => "Southwest"
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
# Returns the team nickname for display
|
|
23
|
+
#
|
|
24
|
+
# @api private
|
|
25
|
+
# @return [String]
|
|
26
|
+
def team_nickname(team)
|
|
27
|
+
return "TBD" unless team
|
|
28
|
+
|
|
29
|
+
team.nickname || team.full_name&.split&.last || "TBD"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns the conference name for a team
|
|
33
|
+
#
|
|
34
|
+
# @api private
|
|
35
|
+
# @return [String]
|
|
36
|
+
def conference_name(detail)
|
|
37
|
+
EAST.include?(detail.abbreviation.to_s) ? "Eastern Conference" : "Western Conference"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns the division name for a team
|
|
41
|
+
#
|
|
42
|
+
# @api private
|
|
43
|
+
# @return [String, nil]
|
|
44
|
+
def division_name(detail)
|
|
45
|
+
division_for_team(detail.abbreviation.to_s)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Looks up the division for a team abbreviation
|
|
49
|
+
#
|
|
50
|
+
# @api private
|
|
51
|
+
# @return [String, nil]
|
|
52
|
+
def division_for_team(abbr)
|
|
53
|
+
division = DIVISIONS.find { |teams, _| teams.include?(abbr) }&.last
|
|
54
|
+
"#{division} Division" if division
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Returns whether the stat represents a championship year
|
|
58
|
+
#
|
|
59
|
+
# @api private
|
|
60
|
+
# @return [Boolean]
|
|
61
|
+
def championship_year?(stat)
|
|
62
|
+
stat.nba_finals_appearance.eql?("LEAGUE CHAMPION")
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module NBA
|
|
2
|
+
class CLI < Thor
|
|
3
|
+
module Formatters
|
|
4
|
+
# Formatters for time-related output
|
|
5
|
+
module TimeFormatters
|
|
6
|
+
# Pattern to match Eastern time format (e.g., "7:30 pm ET")
|
|
7
|
+
# @return [Regexp] the time pattern
|
|
8
|
+
ET_TIME_PATTERN = /\A(\d{1,2}):(\d{2})\s*(am|pm)\s*ET\z/i
|
|
9
|
+
|
|
10
|
+
# Converts Eastern time to local time zone
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
13
|
+
# @param status [String] the status string (may contain ET time)
|
|
14
|
+
# @return [String] the status with time converted to local zone
|
|
15
|
+
def convert_et_to_local(status)
|
|
16
|
+
match = ET_TIME_PATTERN.match(status)
|
|
17
|
+
return status unless match
|
|
18
|
+
|
|
19
|
+
format_local_time(parse_et_time(match))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Parses Eastern time components into a Time object
|
|
23
|
+
#
|
|
24
|
+
# @api private
|
|
25
|
+
# @param match [MatchData] the regex match with hour, minute, am/pm
|
|
26
|
+
# @return [Time] the time in Eastern timezone
|
|
27
|
+
def parse_et_time(match)
|
|
28
|
+
hour = Integer(match[1] || 0)
|
|
29
|
+
minute = Integer(match[2] || 0)
|
|
30
|
+
period = (match[3] || "am").downcase
|
|
31
|
+
|
|
32
|
+
hour = convert_to_24h(hour, period)
|
|
33
|
+
build_et_time(hour, minute)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Converts 12-hour format to 24-hour format
|
|
37
|
+
#
|
|
38
|
+
# @api private
|
|
39
|
+
# @param hour [Integer] the hour in 12-hour format
|
|
40
|
+
# @param period [String] "am" or "pm"
|
|
41
|
+
# @return [Integer] the hour in 24-hour format
|
|
42
|
+
def convert_to_24h(hour, period)
|
|
43
|
+
if period.eql?("am")
|
|
44
|
+
hour.eql?(12) ? 0 : hour
|
|
45
|
+
else
|
|
46
|
+
hour.eql?(12) ? 12 : hour + 12
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Builds a Time object in Eastern timezone
|
|
51
|
+
#
|
|
52
|
+
# @api private
|
|
53
|
+
# @param hour [Integer] the hour in 24-hour format
|
|
54
|
+
# @param minute [Integer] the minute
|
|
55
|
+
# @return [Time] the time in Eastern timezone
|
|
56
|
+
def build_et_time(hour, minute)
|
|
57
|
+
today = Date.today
|
|
58
|
+
Time.new(today.year, today.month, today.day, hour, minute, nil, "-05:00")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Formats a time in the local timezone
|
|
62
|
+
#
|
|
63
|
+
# @api private
|
|
64
|
+
# @param et_time [Time] the time in Eastern timezone
|
|
65
|
+
# @return [String] formatted local time string
|
|
66
|
+
def format_local_time(et_time)
|
|
67
|
+
local_time = et_time.localtime
|
|
68
|
+
zone_abbr = local_time_zone_abbr
|
|
69
|
+
local_time.strftime("%-I:%M %p #{zone_abbr}")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns the local timezone abbreviation
|
|
73
|
+
#
|
|
74
|
+
# @api private
|
|
75
|
+
# @return [String] the timezone abbreviation (e.g., "PST", "EST")
|
|
76
|
+
def local_time_zone_abbr
|
|
77
|
+
Time.now.zone || "ET"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require_relative "formatters/time_formatters"
|
|
2
|
+
require_relative "formatters/team_formatters"
|
|
3
|
+
require_relative "formatters/game_formatters"
|
|
4
|
+
require_relative "formatters/standings_formatters"
|
|
5
|
+
require_relative "formatters/leaders_formatters"
|
|
6
|
+
require_relative "formatters/player_formatters"
|
|
7
|
+
|
|
8
|
+
module NBA
|
|
9
|
+
class CLI < Thor
|
|
10
|
+
# Helper methods for formatting CLI output
|
|
11
|
+
module Formatters
|
|
12
|
+
include TimeFormatters
|
|
13
|
+
include TeamFormatters
|
|
14
|
+
include GameFormatters
|
|
15
|
+
include StandingsFormatters
|
|
16
|
+
include LeadersFormatters
|
|
17
|
+
include PlayerFormatters
|
|
18
|
+
|
|
19
|
+
# Standard label width for formatted output
|
|
20
|
+
#
|
|
21
|
+
# @api private
|
|
22
|
+
# @return [Integer]
|
|
23
|
+
LABEL_WIDTH = 16
|
|
24
|
+
|
|
25
|
+
# Returns the maximum string length from the given values
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
28
|
+
# @return [Integer]
|
|
29
|
+
def max_length(values) = values.map { |v| v.to_s.length }.max
|
|
30
|
+
|
|
31
|
+
# Centers a value within the given width
|
|
32
|
+
#
|
|
33
|
+
# @api private
|
|
34
|
+
# @return [String]
|
|
35
|
+
def center(value, width) = value.to_s.center(width)
|
|
36
|
+
|
|
37
|
+
# Formats a label and value as a single line
|
|
38
|
+
#
|
|
39
|
+
# @api private
|
|
40
|
+
# @return [String]
|
|
41
|
+
def format_label(label, value) = "#{label}: #{value}"
|
|
42
|
+
|
|
43
|
+
# Formats a label with multiple items across lines
|
|
44
|
+
#
|
|
45
|
+
# @api private
|
|
46
|
+
# @return [String]
|
|
47
|
+
def format_multiline_label(label, items)
|
|
48
|
+
indent = " " * (label.length + 2)
|
|
49
|
+
lines = items.each_slice(2).map { |pair| pair.join(", ") }
|
|
50
|
+
first_line = "#{label}: #{lines.first}"
|
|
51
|
+
continuation = lines.drop(1).map { |line| "#{indent}#{line}" }
|
|
52
|
+
([first_line] + continuation).join("\n")
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
module NBA
|
|
2
|
+
class CLI < Thor
|
|
3
|
+
# Helper methods for CLI date parsing and team lookup
|
|
4
|
+
module Helpers
|
|
5
|
+
# Eastern Time offset from UTC in seconds
|
|
6
|
+
# @return [Integer] offset value in seconds
|
|
7
|
+
ET_OFFSET_SECONDS = 5 * 60 * 60
|
|
8
|
+
|
|
9
|
+
# Mapping of conference abbreviations to full names
|
|
10
|
+
# @return [Hash<String, String>] conference mapping
|
|
11
|
+
CONFERENCE_MAP = {"E" => "East", "W" => "West", nil => "Invalid"}.freeze
|
|
12
|
+
|
|
13
|
+
# Parses a date string into a Date object
|
|
14
|
+
#
|
|
15
|
+
# @api private
|
|
16
|
+
# @param date_str [String, nil] the date string
|
|
17
|
+
# @return [Date] the parsed date
|
|
18
|
+
def parse_date(date_str)
|
|
19
|
+
return eastern_time_date if date_str.nil? || date_str.eql?("today")
|
|
20
|
+
return eastern_time_date - 1 if date_str.eql?("yesterday")
|
|
21
|
+
return eastern_time_date + 1 if date_str.eql?("tomorrow")
|
|
22
|
+
|
|
23
|
+
parse_date_string(date_str)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Parses a YYYYMMDD date string
|
|
27
|
+
#
|
|
28
|
+
# @api private
|
|
29
|
+
# @param date_str [String] the date string in YYYYMMDD format
|
|
30
|
+
# @return [Date] the parsed date
|
|
31
|
+
# @raise [SystemExit] if the date string is invalid
|
|
32
|
+
def parse_date_string(date_str)
|
|
33
|
+
Date.strptime(date_str, "%Y%m%d")
|
|
34
|
+
rescue Date::Error
|
|
35
|
+
say("Invalid date '#{date_str}'. Use YYYYMMDD format, 'today', 'yesterday', or 'tomorrow'.")
|
|
36
|
+
raise SystemExit
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns the current date in Eastern Time
|
|
40
|
+
#
|
|
41
|
+
# @api private
|
|
42
|
+
# @return [Date] the current Eastern Time date
|
|
43
|
+
def eastern_time_date = (Time.now.utc - ET_OFFSET_SECONDS).to_date
|
|
44
|
+
|
|
45
|
+
# Finds a team by name or abbreviation
|
|
46
|
+
#
|
|
47
|
+
# @api private
|
|
48
|
+
# @param name [String] the team name or abbreviation
|
|
49
|
+
# @return [Team, nil] the matching team or nil
|
|
50
|
+
def find_team_by_name(name)
|
|
51
|
+
pattern = Regexp.new(name, Regexp::IGNORECASE)
|
|
52
|
+
Teams.all.find { |t| pattern.match?(t.full_name) || pattern.match?(t.abbreviation) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Filters teams by name or abbreviation pattern, or returns all teams
|
|
56
|
+
#
|
|
57
|
+
# @api private
|
|
58
|
+
# @param name [String, nil] the team name or abbreviation pattern to filter by
|
|
59
|
+
# @return [Collection, Array] the matching teams
|
|
60
|
+
def filter_teams(name)
|
|
61
|
+
return Teams.all unless name
|
|
62
|
+
|
|
63
|
+
pattern = Regexp.new(name, Regexp::IGNORECASE)
|
|
64
|
+
Teams.all.select { |team| pattern.match?(team.full_name) || pattern.match?(team.abbreviation) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Normalizes a conference input to full name
|
|
68
|
+
#
|
|
69
|
+
# @api private
|
|
70
|
+
# @param input [String] the conference input (e.g., "e", "E", "East", "w", "W", "West")
|
|
71
|
+
# @return [String] the normalized conference name
|
|
72
|
+
def normalize_conference(input)
|
|
73
|
+
CONFERENCE_MAP.fetch(input.upcase[0].to_s, input)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Fetches standings based on options
|
|
77
|
+
#
|
|
78
|
+
# @api private
|
|
79
|
+
# @return [Collection] the standings collection
|
|
80
|
+
def fetch_standings
|
|
81
|
+
return fetch_conference_standings if options[:conference]
|
|
82
|
+
|
|
83
|
+
options[:season] ? Standings.all(season: options.fetch(:season)) : Standings.all
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Fetches conference-specific standings
|
|
87
|
+
#
|
|
88
|
+
# @api private
|
|
89
|
+
# @return [Collection] the conference standings
|
|
90
|
+
def fetch_conference_standings
|
|
91
|
+
conf = normalize_conference(options.fetch(:conference))
|
|
92
|
+
options[:season] ? Standings.conference(conf, season: options.fetch(:season)) : Standings.conference(conf)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Fetches schedule for a team
|
|
96
|
+
#
|
|
97
|
+
# @api private
|
|
98
|
+
# @param team [Team] the team
|
|
99
|
+
# @return [Collection] the schedule
|
|
100
|
+
def fetch_team_schedule(team)
|
|
101
|
+
season = options[:season]
|
|
102
|
+
season ? Schedule.by_team(team: team, season: season) : Schedule.by_team(team: team)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Fetches roster for a team
|
|
106
|
+
#
|
|
107
|
+
# @api private
|
|
108
|
+
# @param team [Team] the team
|
|
109
|
+
# @return [Collection] the roster
|
|
110
|
+
def fetch_team_roster(team)
|
|
111
|
+
season = options[:season]
|
|
112
|
+
season ? Roster.find(team: team, season: season) : Roster.find(team: team)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Resolves a category name to a Leaders constant
|
|
116
|
+
#
|
|
117
|
+
# @api private
|
|
118
|
+
# @param category [String] the category name
|
|
119
|
+
# @param category_map [Hash] mapping of category names to constant names
|
|
120
|
+
# @return [String] the Leaders constant value
|
|
121
|
+
def resolve_leader_category(category, category_map)
|
|
122
|
+
category_map[category.upcase] || Leaders::PTS
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Fetches games for a date, using live data for today
|
|
126
|
+
#
|
|
127
|
+
# @api private
|
|
128
|
+
# @param date [Date] the date
|
|
129
|
+
# @return [Collection] the games collection
|
|
130
|
+
def fetch_games(date)
|
|
131
|
+
date.eql?(eastern_time_date) ? LiveScoreboard.today : Scoreboard.games(date: date)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
data/lib/nba/cli.rb
CHANGED
|
@@ -1,35 +1,186 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "thor"
|
|
2
|
+
require "date"
|
|
3
|
+
require_relative "cli/formatters"
|
|
4
|
+
require_relative "cli/display"
|
|
5
|
+
require_relative "cli/helpers"
|
|
2
6
|
|
|
3
7
|
module NBA
|
|
8
|
+
# Command-line interface for the NBA gem
|
|
9
|
+
#
|
|
10
|
+
# @api public
|
|
4
11
|
class CLI < Thor
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
include Formatters
|
|
13
|
+
include Display
|
|
14
|
+
include Helpers
|
|
15
|
+
|
|
16
|
+
# Mapping of category names and abbreviations to Leaders constants
|
|
17
|
+
# @return [Hash<String, String>] category mapping
|
|
18
|
+
CATEGORY_MAP = {
|
|
19
|
+
"PTS" => "PTS", "POINTS" => "PTS",
|
|
20
|
+
"REB" => "REB", "REBOUNDS" => "REB",
|
|
21
|
+
"AST" => "AST", "ASSISTS" => "AST",
|
|
22
|
+
"STL" => "STL", "STEALS" => "STL",
|
|
23
|
+
"BLK" => "BLK", "BLOCKS" => "BLK",
|
|
24
|
+
"FG_PCT" => "FG_PCT", "FG3_PCT" => "FG3_PCT", "FT_PCT" => "FT_PCT"
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
class_option :version, type: :boolean, aliases: "-v", desc: "Print version and exit"
|
|
28
|
+
|
|
29
|
+
remove_command :tree
|
|
30
|
+
|
|
31
|
+
# Returns whether Thor should exit on failure
|
|
32
|
+
#
|
|
33
|
+
# @api public
|
|
34
|
+
# @example
|
|
35
|
+
# NBA::CLI.exit_on_failure? #=> true
|
|
36
|
+
# @return [Boolean] true if CLI should exit on failure
|
|
37
|
+
def self.exit_on_failure?
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
desc "games", "Retrieve games' scoreboard for a date"
|
|
42
|
+
method_option :date, type: :string, aliases: "-d", desc: "Date (YYYYMMDD, 'today', or 'yesterday')"
|
|
43
|
+
# Retrieves and displays games for a specified date
|
|
44
|
+
#
|
|
45
|
+
# @api public
|
|
46
|
+
# @example
|
|
47
|
+
# cli = NBA::CLI.new
|
|
48
|
+
# cli.games
|
|
49
|
+
# @return [void]
|
|
7
50
|
def games
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
51
|
+
date = parse_date(options[:date])
|
|
52
|
+
games_list = fetch_games(date)
|
|
53
|
+
games_list.empty? ? say("No games found for #{date}") : display_games(games_list)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
desc "teams [NAME]", "List all teams or search by name"
|
|
57
|
+
method_option :roster, type: :boolean, aliases: "-r", default: false, desc: "Include roster"
|
|
58
|
+
# Lists all teams or searches for teams by name
|
|
59
|
+
#
|
|
60
|
+
# @api public
|
|
61
|
+
# @example
|
|
62
|
+
# cli = NBA::CLI.new
|
|
63
|
+
# cli.teams("GSW")
|
|
64
|
+
# @param name [String, nil] the team name or abbreviation to search for
|
|
65
|
+
# @return [void]
|
|
66
|
+
def teams(name = nil)
|
|
67
|
+
matching_teams = filter_teams(name)
|
|
68
|
+
if matching_teams.empty?
|
|
69
|
+
say("No team found with name '#{name}'")
|
|
12
70
|
else
|
|
13
|
-
|
|
71
|
+
display_teams(matching_teams, options.fetch(:roster), detailed: name)
|
|
14
72
|
end
|
|
73
|
+
end
|
|
15
74
|
|
|
16
|
-
|
|
75
|
+
desc "player NAME", "Search for a player by name"
|
|
76
|
+
# Searches for players by name
|
|
77
|
+
#
|
|
78
|
+
# @api public
|
|
79
|
+
# @example
|
|
80
|
+
# cli = NBA::CLI.new
|
|
81
|
+
# cli.player("LeBron")
|
|
82
|
+
# @param name [String] the player name to search for
|
|
83
|
+
# @return [void]
|
|
84
|
+
def player(name)
|
|
85
|
+
pattern = Regexp.new(name, Regexp::IGNORECASE)
|
|
86
|
+
matching = Players.all.select { |p| pattern.match?(p.full_name) }
|
|
87
|
+
if matching.empty?
|
|
88
|
+
say("No player found with name '#{name}'")
|
|
89
|
+
elsif matching.one?
|
|
90
|
+
matching.each { |p| display_player(p) }
|
|
91
|
+
else
|
|
92
|
+
display_players(matching)
|
|
93
|
+
end
|
|
17
94
|
end
|
|
18
95
|
|
|
19
|
-
desc "
|
|
20
|
-
method_option :
|
|
21
|
-
method_option :
|
|
22
|
-
|
|
23
|
-
|
|
96
|
+
desc "standings", "Display current league standings"
|
|
97
|
+
method_option :conference, type: :string, aliases: "-c", desc: "Filter by conference (East/West)"
|
|
98
|
+
method_option :season, type: :numeric, aliases: "-s", desc: "Season year (e.g., 2024)"
|
|
99
|
+
# Displays current league standings
|
|
100
|
+
#
|
|
101
|
+
# @api public
|
|
102
|
+
# @example
|
|
103
|
+
# cli = NBA::CLI.new
|
|
104
|
+
# cli.standings
|
|
105
|
+
# @return [void]
|
|
106
|
+
def standings
|
|
107
|
+
display_standings(fetch_standings)
|
|
108
|
+
end
|
|
24
109
|
|
|
25
|
-
|
|
26
|
-
|
|
110
|
+
desc "leaders [CATEGORY]", "Display league leaders for a statistical category"
|
|
111
|
+
method_option :season, type: :numeric, aliases: "-s", desc: "Season year (e.g., 2024)"
|
|
112
|
+
method_option :limit, type: :numeric, aliases: "-l", default: 10, desc: "Number of leaders"
|
|
113
|
+
# Displays league leaders for a statistical category
|
|
114
|
+
#
|
|
115
|
+
# @api public
|
|
116
|
+
# @example
|
|
117
|
+
# cli = NBA::CLI.new
|
|
118
|
+
# cli.leaders("PTS")
|
|
119
|
+
# @param category_name [String] the stat category (PTS, REB, AST, STL, BLK, FG_PCT, FG3_PCT, FT_PCT)
|
|
120
|
+
# @return [void]
|
|
121
|
+
def leaders(category_name = "PTS")
|
|
122
|
+
category = resolve_leader_category(category_name, CATEGORY_MAP)
|
|
123
|
+
leaders_list = if options[:season]
|
|
124
|
+
Leaders.find(category: category, limit: options.fetch(:limit),
|
|
125
|
+
season: options.fetch(:season))
|
|
27
126
|
else
|
|
28
|
-
|
|
29
|
-
team.pretty_print
|
|
30
|
-
puts "-" * 42
|
|
31
|
-
end
|
|
127
|
+
Leaders.find(category: category, limit: options.fetch(:limit))
|
|
32
128
|
end
|
|
129
|
+
display_leaders(leaders_list, category_name)
|
|
33
130
|
end
|
|
131
|
+
|
|
132
|
+
desc "schedule TEAM", "Display schedule for a team"
|
|
133
|
+
method_option :season, type: :numeric, aliases: "-s", desc: "Season year (e.g., 2024)"
|
|
134
|
+
# Displays schedule for a team
|
|
135
|
+
#
|
|
136
|
+
# @api public
|
|
137
|
+
# @example
|
|
138
|
+
# cli = NBA::CLI.new
|
|
139
|
+
# cli.schedule("Lakers")
|
|
140
|
+
# @param team_name [String] the team name or abbreviation
|
|
141
|
+
# @return [void]
|
|
142
|
+
def schedule(team_name)
|
|
143
|
+
team = find_team_by_name(team_name)
|
|
144
|
+
if team
|
|
145
|
+
schedule_list = fetch_team_schedule(team)
|
|
146
|
+
display_schedule(schedule_list, team)
|
|
147
|
+
else
|
|
148
|
+
say("No team found with name '#{team_name}'")
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
desc "roster TEAM", "Display roster for a team"
|
|
153
|
+
method_option :season, type: :numeric, aliases: "-s", desc: "Season year (e.g., 2024)"
|
|
154
|
+
# Displays roster for a team
|
|
155
|
+
#
|
|
156
|
+
# @api public
|
|
157
|
+
# @example
|
|
158
|
+
# cli = NBA::CLI.new
|
|
159
|
+
# cli.roster("Lakers")
|
|
160
|
+
# @param team_name [String] the team name or abbreviation
|
|
161
|
+
# @return [void]
|
|
162
|
+
def roster(team_name)
|
|
163
|
+
team = find_team_by_name(team_name)
|
|
164
|
+
if team
|
|
165
|
+
roster_list = fetch_team_roster(team)
|
|
166
|
+
display_roster(roster_list, team)
|
|
167
|
+
else
|
|
168
|
+
say("No team found with name '#{team_name}'")
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
desc "version", "Display version information"
|
|
173
|
+
# Displays version information
|
|
174
|
+
#
|
|
175
|
+
# @api public
|
|
176
|
+
# @example
|
|
177
|
+
# cli = NBA::CLI.new
|
|
178
|
+
# cli.version
|
|
179
|
+
# @return [void]
|
|
180
|
+
def version
|
|
181
|
+
say("nba #{VERSION}")
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
map %w[-v --version] => :version
|
|
34
185
|
end
|
|
35
186
|
end
|
data/lib/nba/client.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require_relative "connection"
|
|
2
|
+
|
|
3
|
+
module NBA
|
|
4
|
+
# API client for making requests to the NBA Stats API
|
|
5
|
+
class Client
|
|
6
|
+
# Makes a GET request to the specified path
|
|
7
|
+
#
|
|
8
|
+
# @api public
|
|
9
|
+
# @example
|
|
10
|
+
# client.get("commonplayerinfo?PlayerID=2544")
|
|
11
|
+
# @param path [String] the API path to request
|
|
12
|
+
# @return [String] the response body
|
|
13
|
+
def get(path) = connection.get(path)
|
|
14
|
+
|
|
15
|
+
# Returns the connection used for HTTP requests
|
|
16
|
+
#
|
|
17
|
+
# @api private
|
|
18
|
+
# @return [Connection] the connection instance
|
|
19
|
+
attr_reader :connection
|
|
20
|
+
|
|
21
|
+
# Initializes a new Client object
|
|
22
|
+
#
|
|
23
|
+
# @api public
|
|
24
|
+
# @example
|
|
25
|
+
# client = NBA::Client.new
|
|
26
|
+
# @param connection [Connection] the connection to use for requests
|
|
27
|
+
# @return [NBA::Client] a new client instance
|
|
28
|
+
def initialize(connection: Connection.new)
|
|
29
|
+
@connection = connection
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Default client instance
|
|
34
|
+
CLIENT = Client.new
|
|
35
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require "equalizer"
|
|
2
|
+
require "forwardable"
|
|
3
|
+
|
|
4
|
+
module NBA
|
|
5
|
+
# Represents a collection of objects
|
|
6
|
+
class Collection
|
|
7
|
+
extend Forwardable
|
|
8
|
+
include Equalizer.new(:elements)
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
# @!method size
|
|
12
|
+
# Returns the number of elements in the collection
|
|
13
|
+
# @api public
|
|
14
|
+
# @example
|
|
15
|
+
# collection.size #=> 3
|
|
16
|
+
# @return [Integer] the number of elements
|
|
17
|
+
|
|
18
|
+
# @!method empty?
|
|
19
|
+
# Returns true if the collection has no elements
|
|
20
|
+
# @api public
|
|
21
|
+
# @example
|
|
22
|
+
# collection.empty? #=> false
|
|
23
|
+
# @return [Boolean] true if empty, false otherwise
|
|
24
|
+
|
|
25
|
+
# @!method first
|
|
26
|
+
# Returns the first element in the collection
|
|
27
|
+
# @api public
|
|
28
|
+
# @example
|
|
29
|
+
# collection.first #=> player1
|
|
30
|
+
# @return [Object, nil] the first element or nil if empty
|
|
31
|
+
|
|
32
|
+
# @!method last
|
|
33
|
+
# Returns the last element in the collection
|
|
34
|
+
# @api public
|
|
35
|
+
# @example
|
|
36
|
+
# collection.last #=> player3
|
|
37
|
+
# @return [Object, nil] the last element or nil if empty
|
|
38
|
+
|
|
39
|
+
# @!method length
|
|
40
|
+
# Returns the number of elements in the collection
|
|
41
|
+
# @api public
|
|
42
|
+
# @example
|
|
43
|
+
# collection.length #=> 3
|
|
44
|
+
# @return [Integer] the number of elements
|
|
45
|
+
|
|
46
|
+
# @!method count
|
|
47
|
+
# Returns the number of elements in the collection
|
|
48
|
+
# @api public
|
|
49
|
+
# @example
|
|
50
|
+
# collection.count #=> 3
|
|
51
|
+
# @return [Integer] the number of elements
|
|
52
|
+
|
|
53
|
+
def_delegators :elements, :size, :empty?, :first, :last
|
|
54
|
+
|
|
55
|
+
alias_method :length, :size
|
|
56
|
+
alias_method :count, :size
|
|
57
|
+
|
|
58
|
+
# Returns the elements in the collection
|
|
59
|
+
#
|
|
60
|
+
# @api private
|
|
61
|
+
# @return [Array] the elements
|
|
62
|
+
attr_reader :elements
|
|
63
|
+
|
|
64
|
+
# Initializes a new Collection
|
|
65
|
+
#
|
|
66
|
+
# @api public
|
|
67
|
+
# @example
|
|
68
|
+
# collection = NBA::Collection.new([player1, player2])
|
|
69
|
+
# @param elements [Array] the elements in the collection
|
|
70
|
+
# @return [NBA::Collection] a new collection instance
|
|
71
|
+
def initialize(elements = [])
|
|
72
|
+
@elements = elements
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Iterates over the elements in the collection
|
|
76
|
+
#
|
|
77
|
+
# @api public
|
|
78
|
+
# @example
|
|
79
|
+
# collection.each { |element| puts element }
|
|
80
|
+
# @yield [element] yields each element to the block
|
|
81
|
+
# @return [Enumerator, self] an enumerator or self
|
|
82
|
+
def each(&block)
|
|
83
|
+
return enum_for unless block
|
|
84
|
+
|
|
85
|
+
elements.each(&block)
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|