espn_pub 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4dee5305666108de85913d5ef82a426b3e43c7c011833c4f9f0be06d9ebb6ae6
4
+ data.tar.gz: aa60cb29dbfe5abba1e77b75bc96fe4b4bb6cb90c00318ff59934b5171528898
5
+ SHA512:
6
+ metadata.gz: ca5aeb78fe7c56960d27a55e58e4763652527dece17663cf02e5847fd73349f9aa7d1293db8d8b7751c0d250d3a4b065ee1c3e98a8774f73719829fd1a36e87a
7
+ data.tar.gz: a5dc7c9b283be22e3d2813955e122fd0916a9fec69821f551016957a139ce55f1fd55b6cbb745773857b4f1216ed5d49080200472102c6360e4bc4aa6b26ab6f
data/README.md ADDED
@@ -0,0 +1 @@
1
+ # espn-pub-rb
data/espn_pub.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/espn_pub/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'espn_pub'
7
+ spec.version = EspnPub::VERSION
8
+ spec.authors = ['Jeffrey Bowman']
9
+ spec.email = ['bowmanjeffrey12@gmail.com']
10
+ spec.summary = 'A Ruby client for the public ESPN API'
11
+ spec.description = "Fetch sports data from ESPN's public API — teams, athletes, scoreboards, and more."
12
+ spec.homepage = 'https://github.com/bowmanje/espn-pub-rb'
13
+ spec.license = 'MIT'
14
+ spec.required_ruby_version = '>= 3.3.0'
15
+ spec.metadata = {
16
+ 'homepage_uri' => spec.homepage,
17
+ 'source_code_uri' => spec.homepage
18
+ }
19
+
20
+ spec.files = Dir.glob('{lib,sig}/**/*', File::FNM_DOTMATCH)
21
+ .reject { |f| File.directory?(f) } +
22
+ %w[espn_pub.gemspec README.md]
23
+
24
+ spec.require_paths = ['lib']
25
+ spec.add_dependency 'json', '~> 2.6'
26
+ spec.add_dependency 'net-http', '~> 0.3'
27
+ spec.add_dependency 'uri', '~> 0.11'
28
+ spec.add_dependency 'date', '~> 3.3'
29
+ spec.add_development_dependency 'rake', '~> 13.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.13'
31
+ spec.add_development_dependency 'rubocop', '~> 1.65'
32
+ spec.add_development_dependency 'rubocop-rspec', '~> 3.0'
33
+ spec.add_development_dependency 'webmock', '~> 3.23'
34
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module EspnPub
7
+ # Client for making requests to the ESPN public API.
8
+ class Client
9
+ # Raised when the API returns an unexpected HTTP response code.
10
+ class UnexpectedResponseCodeError < StandardError; end
11
+
12
+ BASE_URI = 'https://site.api.espn.com/'
13
+ API_VERSION = 'v2'
14
+
15
+ attr_reader :uri, :version
16
+
17
+ # Initialize a new Client.
18
+ #
19
+ # @param base_uri [String] The base URI for ESPN API requests.
20
+ # @param version [String] The API version string.
21
+ def initialize(base_uri:, version:)
22
+ @uri = get_uri(base_uri)
23
+ @version = version
24
+ end
25
+
26
+ # Send a GET request to the specified API path.
27
+ #
28
+ # @param path [String] The request path to fetch from ESPN.
29
+ # @return [Hash] The parsed JSON response.
30
+ # @raise [UnexpectedResponseCodeError] if the response status is not 200.
31
+ def send_request(path)
32
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
33
+ http.request_get path
34
+ end
35
+
36
+ raise UnexpectedResponseCodeError, "Unexpected response code: #{response.code}" unless response.code.to_i == 200
37
+
38
+ JSON.parse response.body
39
+ end
40
+
41
+ private
42
+
43
+ # Parse a string into a URI object.
44
+ #
45
+ # @param uri [String] The URI string to parse.
46
+ # @return [URI]
47
+ def get_uri(uri)
48
+ URI uri
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EspnPub
4
+ module Entities
5
+ # Base entity that holds a shared ESPN API client.
6
+ class Base
7
+ attr_reader :client
8
+
9
+ # Initialize the base entity and create the shared client.
10
+ #
11
+ # @return [void]
12
+ def initialize
13
+ @client = init_client
14
+ end
15
+
16
+ private
17
+ # Build a new EspnPub::Client for API requests.
18
+ #
19
+ # @return [EspnPub::Client]
20
+ def init_client
21
+ EspnPub::Client.new(
22
+ base_uri: Client::BASE_URI,
23
+ version: Client::API_VERSION,
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EspnPub
4
+ module Entities
5
+ # Represents a game between two teams.
6
+ class Game < Base
7
+ attr_reader :id, :home_team_id, :away_team_id, :date
8
+
9
+ # Initialize a Game entity.
10
+ #
11
+ # @param id [String] The game identifier.
12
+ # @param home_team_id [String] The home team identifier.
13
+ # @param away_team_id [String] The away team identifier.
14
+ # @param date [DateTime] The scheduled game date.
15
+ def initialize(id:, home_team_id:, away_team_id:, date:)
16
+ @id = id
17
+ @home_team_id = home_team_id
18
+ @away_team_id = away_team_id
19
+ @date = date
20
+ super()
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module EspnPub
6
+ module Entities
7
+ # Represents a sports league, eg. NBA, NFL, etc.
8
+ class League < Base
9
+ # Supported league names.
10
+ module NAME
11
+ NBA = 'nba'
12
+ NFL = 'nfl'
13
+ end
14
+
15
+ TEAMS_PATH = '/apis/site/%s/sports/%s/%s/teams'
16
+ GAMES_PATH = '/apis/site/%s/sports/%s/%s/scoreboard'
17
+
18
+ NAME_TO_SPORT = {
19
+ 'nba' => 'basketball',
20
+ 'nfl' => 'football'
21
+ }.freeze
22
+
23
+ attr_reader :name
24
+
25
+ # Initialize a League instance.
26
+ #
27
+ # @param name [String] The league identifier string.
28
+ def initialize(name)
29
+ @name = name
30
+ super()
31
+ end
32
+
33
+ # Fetch the teams for this league.
34
+ #
35
+ # @return [Array<EspnPub::Entities::Team>]
36
+ def teams
37
+ unless defined?(@teams)
38
+ begin
39
+ path = format TEAMS_PATH, client.version, self.sport, name
40
+ teams_resp = client.send_request(path)
41
+ @teams = (teams_resp.dig('sports', 0, 'leagues', 0, 'teams') || []).map do |team_data|
42
+ EspnPub::Entities::Team.new(
43
+ id: team_data.dig('team', 'id'),
44
+ name: team_data.dig('team', 'name'),
45
+ location: team_data.dig('team', 'location'),
46
+ abbreviation: team_data.dig('team', 'abbreviation'),
47
+ sport: sport,
48
+ league: name
49
+ )
50
+ end
51
+ rescue Client::UnexpectedResponseCodeError => e
52
+ warn "Failed to fetch teams for league #{name}: #{e.message}"
53
+ return []
54
+ end
55
+ end
56
+
57
+ @teams
58
+ end
59
+
60
+ # Fetch games for this league.
61
+ #
62
+ # @param date [Date, DateTime, nil] An optional date to filter games.
63
+ # @return [Array<EspnPub::Entities::Game>]
64
+ def games(date: nil)
65
+ begin
66
+ path = format GAMES_PATH, client.version, self.sport, name
67
+ path += "?dates=#{date.strftime('%Y%m%d')}" if date
68
+ games_resp = client.send_request(path)
69
+ (games_resp.dig('events') || []).map do |game_data|
70
+ EspnPub::Entities::Game.new(
71
+ id: game_data['id'],
72
+ home_team_id: game_data.dig('competitions', 0, 'competitors', 0, 'id'),
73
+ away_team_id: game_data.dig('competitions', 0, 'competitors', 1, 'id'),
74
+ date: DateTime.parse(game_data['date'])
75
+ )
76
+ end
77
+ rescue Client::UnexpectedResponseCodeError => e
78
+ warn "Failed to fetch games for league #{name}: #{e.message}"
79
+ return []
80
+ end
81
+ end
82
+
83
+ # Return the sport name for this league.
84
+ #
85
+ # @return [String, nil] The sport name or nil when unknown.
86
+ def sport
87
+ NAME_TO_SPORT[name]
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EspnPub
4
+ module Entities
5
+ # Represents a player on a team.
6
+ class Player < Base
7
+ attr_reader :id,
8
+ :sport,
9
+ :league,
10
+ :first_name,
11
+ :last_name,
12
+ :position,
13
+ :team_id
14
+
15
+ # Initialize a Player entity.
16
+ #
17
+ # @param id [String] The player identifier.
18
+ # @param sport [String] The sport name.
19
+ # @param league [String] The league identifier.
20
+ # @param first_name [String, nil] The player's first name.
21
+ # @param last_name [String, nil] The player's last name.
22
+ # @param position [String, nil] The player's position abbreviation.
23
+ # @param team_id [String, nil] The identifier of the player's team.
24
+ def initialize(id:, sport:, league:, first_name: nil, last_name: nil, position: nil, team_id: nil)
25
+ @id = id
26
+ @sport = sport
27
+ @league = league
28
+ @first_name = first_name
29
+ @last_name = last_name
30
+ @position = position
31
+ @team_id = team_id
32
+ super()
33
+ end
34
+
35
+ # Return the player's full name.
36
+ #
37
+ # @return [String] The player's full name.
38
+ def full_name
39
+ @full_name ||= first_name + ' ' + last_name
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EspnPub
4
+ module Entities
5
+ # Represents a sports team, eg. Miami Heat, New England Patriots, etc.
6
+ class Team < Base
7
+
8
+ ROSTER_PATH = '/apis/site/%s/sports/%s/%s/teams/%s/roster'
9
+
10
+ attr_reader :id,
11
+ :name,
12
+ :location,
13
+ :abbreviation,
14
+ :sport,
15
+ :league
16
+
17
+ # Initialize a Team entity.
18
+ #
19
+ # @param id [String] The team identifier.
20
+ # @param name [String] The team name.
21
+ # @param location [String] The team location.
22
+ # @param abbreviation [String] The team abbreviation.
23
+ # @param sport [String] The sport name.
24
+ # @param league [String] The league identifier.
25
+ def initialize(id:, name:, location:, abbreviation:, sport:, league:)
26
+ @id = id
27
+ @name = name
28
+ @location = location
29
+ @abbreviation = abbreviation
30
+ @sport = sport
31
+ @league = league
32
+ super()
33
+ end
34
+
35
+ # Fetch the roster for this team.
36
+ #
37
+ # @return [Array<EspnPub::Entities::Player>]
38
+ def players
39
+ unless defined?(@roster)
40
+ begin
41
+ path = format ROSTER_PATH, client.version, sport, league, id
42
+ roster_resp = client.send_request(path)
43
+ @roster = (roster_resp.dig('athletes') || []).map do |athlete_data|
44
+ player = EspnPub::Entities::Player.new(
45
+ id: athlete_data['id'],
46
+ sport: sport,
47
+ league: league,
48
+ first_name: athlete_data['firstName'],
49
+ last_name: athlete_data['lastName'],
50
+ position: athlete_data['position']['abbreviation'],
51
+ team_id: id
52
+ )
53
+ end
54
+ rescue Client::UnexpectedResponseCodeError => e
55
+ warn "Failed to fetch roster for team #{name} (#{id}): #{e.message}"
56
+ return []
57
+ end
58
+ end
59
+
60
+ @roster
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EspnPub
4
+ VERSION = '0.1.0'
5
+ end
data/lib/espn_pub.rb ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Namespace for the ESPN public API client library.
4
+ #
5
+ # This gem exposes entities and a client for fetching leagues, teams,
6
+ # players, and games from ESPN's public API.
7
+
8
+ require_relative 'espn_pub/version'
9
+ require_relative 'espn_pub/client'
10
+ require_relative 'espn_pub/entities/base'
11
+ require_relative 'espn_pub/entities/league'
12
+ require_relative 'espn_pub/entities/team'
13
+ require_relative 'espn_pub/entities/player'
14
+ require_relative 'espn_pub/entities/game'
15
+
16
+ module EspnPub
17
+ end
18
+ # --- IGNORE ---
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: espn_pub
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jeffrey Bowman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-05-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: net-http
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: uri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.11'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: date
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.13'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.13'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.65'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.65'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.23'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.23'
139
+ description: Fetch sports data from ESPN's public API — teams, athletes, scoreboards,
140
+ and more.
141
+ email:
142
+ - bowmanjeffrey12@gmail.com
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - README.md
148
+ - espn_pub.gemspec
149
+ - lib/espn_pub.rb
150
+ - lib/espn_pub/client.rb
151
+ - lib/espn_pub/entities/base.rb
152
+ - lib/espn_pub/entities/game.rb
153
+ - lib/espn_pub/entities/league.rb
154
+ - lib/espn_pub/entities/player.rb
155
+ - lib/espn_pub/entities/team.rb
156
+ - lib/espn_pub/version.rb
157
+ homepage: https://github.com/bowmanje/espn-pub-rb
158
+ licenses:
159
+ - MIT
160
+ metadata:
161
+ homepage_uri: https://github.com/bowmanje/espn-pub-rb
162
+ source_code_uri: https://github.com/bowmanje/espn-pub-rb
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: 3.3.0
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubygems_version: 3.5.3
179
+ signing_key:
180
+ specification_version: 4
181
+ summary: A Ruby client for the public ESPN API
182
+ test_files: []